本文主要是介绍ucore_lab7,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
练习1 理解内核级信号量的实现和基于内核级信号量的哲学家就餐问题
完成练习0后,建议大家比较一下(可用kdiff3等文件比较软件)个人完成的lab6和练习0完成后的刚> 修改的lab7之间的区别,分析了解lab7采用信号量的执行过程。执行make grade,大部分测试用应该通过。
[练习1.1]请在实验报告中给出内核级信号量的设计描述,并说其大致执行流流程。
答: 在ucore中,通过sem.h,sem.c实现了信号量。
其中,信号的数据结构是这样的:
int value;
wait_queue_t wait_queue;
对于V操作和P操作,分别用up和down函数来对应。
down()函数:
开中断,首先对sem.value >0 ,对sem.value减1,关闭中断,proc可以获得相应的资源。如果sem.value <= 0,那么就需要将proc放入等待队列,并进行调度 schedule(),直到别的占用此资源的proc释放该资源并唤醒等待的proc, wait_current_del(&(sem->wait_queue)在等待队列中删除wait wait);
up()函数:
首先关中断,检查sem.wait_queue是否为空,如果为空,说明没有在等待此资源的proc,所以将sem.value加1;如果不为空,那么说明有proc在等待此资源,那么唤醒该proc,开中断。
其中关中断是通过local_intr_save(intr_flag);实现的,这个函数只是保存了一些中断的变量,尝试去关闭中断,如果中断已经关闭,则不执行。
local_intr_restore(intr_flag);使能中断。
[练习1.2]请在实验报告中给出给用户态进程/线程提供信号量机制的设计方案,并比较说明给内核级提供信号量机制的异同。
答:用户态的进行/线程的信号量的数据结构和内核级的是一样的。
对于用户态的线程/进程使用信号量机制,应该首先通过系统调用进行sem的初始化,设置sem.value以及sem.wait_queue,而在初始化之后,在使用这个信号量时,通过P操作与V操作,也是通过系统调用进入到内核中进行处理,简称是否等待或者释放资源。
不同: 在用户态使用信号量时,需要进行系统调用进入到内核态进行操作。
练习2 完成内核级条件变量和基于内核级条件变量的哲学家就餐问题
首先掌握管程机制,然后基于信号量实现完成条件变量实现,然后用管程机制实现哲学家就餐问题的解决方案(基于条件变量)。
[练习2.1]请在实验报告中给出内核级条件变量的设计描述,并说其大致执行流流程。
答:数据结构如下:
typedef struct condvar{semaphore_t sem; //表示等待的队列int count; //等待的队列的数目monitor_t * owner; //相对应的管程
}condvar_t;
typedef struct monitor{semaphore_t mutex; //互斥量semaphore_t next; //用来实现Hoare机制int next_count; condvar_t * cv; //条件变量
}monitor_t;
monitor_init()、cond_signal()、cond_wait()函数。
monitor_init()函数:
对条件变量进行初始化,设置next_count为0,对mutex,next进行初始化, sem_init(&(mtp->mutex), 1); //unlocked
并分配num个condvar_t,设置cv的count为0,初始化cv的sem和owner。
for(i=0; i<num_cv; i++){mtp->cv[i].count=0; sem_init(&(mtp->cv[i].sem),0); mtp->cv[i].owner=mtp; }
cond_signal()函数: 唤醒睡在条件变量上的线程
如果cv的count>0,说明有proc在等待,那么需要唤醒等待在cv.sem上的proc,并使自己进行睡眠,同时monitor.next_count++,在被唤醒后执行monitor.next_count–;如果cv的count == 0,说明没有proc在等待cv.sem,直接返回函数。
for(i=0; i<num_cv; i++){if(cvp ->count > 0){ cvp->owner -> next_count ++; up(&(cvp->sem)); down(&(cvp -> owner->next));//这就是Hoare机制,直接切换回等待条件变量的进程,等其执行完毕,这个线程才能执行 count-- cvp -> owner -> next_count --;}
Hansen机制:
if(cvp ->count > 0){ up(&(cvp->sem)); }
其中另外一种机制是Hansen机制:cond_wait()函数:使线程睡在条件变量上
先将cv.count++,如果monitor.next_count >0,说明有进程执行cond_signal()函数并且睡着了,此时唤醒此proc;否则的话,说明目前没有因为执行了cond_signal()函数的proc睡着,此时唤醒因为互斥条件mutex无法进入管程的proc。在这之后,使A在cv.sem上进行等待并进行调度,如果A睡醒了,则cv.count–。
cvp -> count ++;等待的进程数目+1 if(cvp -> owner->next_count > 0){up(&(cvp -> owner -> next)); //唤醒另一个给出条件变量的进程} else{ up(&(cvp -> owner -> mutex)); //释放mutex,是其他进程得到monitor进入管程 } down(&(cvp -> sem)); //等待,在sem cvp -> count --; //等待的数目-1
Hansen机制
//wait 的时候,等待的进程数+1,然后wait在sem上,释放mutex cvp->count++; up(&cvp->owner->mutex); down(&cvp->sem); //上锁,count -1 down(&cvp->owner->mutex); cvp->count--;
哲学家问题
信号量的实现:
semphore_t mutex 临界区互斥信号量
semphore_t s[N] 每个哲学家一个信号量
试图得到叉子
首先判断左右的状态不是“eatting”然后是自己的状态变成“EATING” up(s[i]);
拿叉子
down(&mutex)进入临界区
state_sema[i]=HUNGRY 记录饥饿
试图得到叉子如果得到up(s[i])
up(&mutex)离开临界区
down(&s[i])如果得不到叉子就等待
放叉子
down(&mutex)进入临界区
state_sema[i]=THINKING 改变状态为就餐结束
phi_test_sema(LEFT)看左邻局能否进餐
phi_test_sema(RIGHT)看一下右邻居能否进餐
up(&mutex)离开临界区
管程的实现
数据结构:
struct proc_struct *philosopher_proc_condvar[N]; // N philosopher
int state_condvar[N]; // the philosopher’s state: EATING, HUNGARY, THINKING
monitor_t mt, *mtp=&mt; // monitor
试图得到叉子
void phi_test_condvar (i) {
if(state_condvar[i]==HUNGRY&&state_condvar[LEFT]!=EATING&&state_condvar[RIGHT]!=EATING) {cprintf("phi_test_condvar: state_condvar[%d] will eating\n",i);state_condvar[i] = EATING ;cprintf("phi_test_condvar: signal self_cv[%d] \n",i);cond_signal(&mtp->cv[i]) ; //得到条件变量cv[i]
}
}
拿叉子
void phi_take_forks_condvar(int i) {down(&(mtp->mutex)); //进入管程的临界区
//--------into routine in monitor--------------// LAB7 EXERCISE1: 2013011424// I am hungry// try to get fork
//--------leave routine in monitor--------------state_condvar[i] = HUNGRY; //改变状态为 HUNGRYphi_test_condvar(i); //试图拿到叉子 if(state_condvar[i] != EATING){cond_wait(&mtp -> cv[i]);}if(mtp->next_count>0) //Hoare机制up(&(mtp->next));elseup(&(mtp->mutex));
}
放叉子
void phi_put_forks_condvar(int i) {down(&(mtp->mutex));//进入临界区//--------into routine in monitor--------------// LAB7 EXERCISE1: 2013011424// I ate over// test left and right neighbors
//--------leave routine in monitor--------------state_condvar[i] = THINKING; 改变状态为THINKINGphi_test_condvar( LEFT); //左边的得到叉子phi_test_condvar(RIGHT); //右边的得到叉子if(mtp->next_count>0)up(&(mtp->next));elseup(&(mtp->mutex)); //离开临界区
}
[练习2.2]请在实验报告中给出给用户态进程/线程提供条件变量机制的设计方案,并比较说明给内核级提供条件变量机制的异同。
答用户级别的的管程,则通过初始化condvar 然后通过系统调用在用户级别实现管程的处理函数。不同点:用户需要系统调用。
这篇关于ucore_lab7的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!