ucore_lab7

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/TH_NUM/article/details/51496707

练习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; //改变状态为 HUNGRY
 phi_test_condvar(i); //试图拿到叉子 
 if(state_condvar[i] != EATING){
     cond_wait(&mtp -> cv[i]);
 }
 if(mtp->next_count>0) //Hoare机制
     up(&(mtp->next));
  else
     up(&(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; 改变状态为THINKING
 phi_test_condvar( LEFT); //左边的得到叉子
 phi_test_condvar(RIGHT); //右边的得到叉子
 if(mtp->next_count>0)
    up(&(mtp->next));
 else
    up(&(mtp->mutex)); //离开临界区
}


[练习2.2]请在实验报告中给出给用户态进程/线程提供条件变量机制的设计方案,并比较说明给内核级提供条件变量机制的异同。

用户级别的的管程,则通过初始化condvar 然后通过系统调用在用户级别实现管程的处理函数。不同点:用户需要系统调用。

展开阅读全文

没有更多推荐了,返回首页