管程

作用

管程保证了同一时间只能有一个进程在管程内活动,使用condition变量让进入管程而无法继续执行的进程阻塞自己。

例子

先来看一段有问题的代码:

#define TRUE 1
#define MAX 100

void insert_item(int);
int  remove_item();

int count = 0;

void producer()
{
    int item;

    while(TRUE)
    {
        item = produce_item(); 
        if( count == MAX ) sleep();
        insert_item(item);
        count += 1;
        if( count == 1) wakeup(consumer); /*buffer由空变非空后唤醒挂起的消费者*/
    }
}

void consumer()
{
    int item;

    while(TRUE)
    {
        if( count == 0 ) sleep();
        item = remove_item();
        count -= 1;
        /*buffer由满变不满后唤醒生产者*/
        if( count == MAX - 1 ) wakeup(producer);
        consume_item(item);         
    }

如果producer在consumer sleep之前发送wakeup信号则会导致错误:比如消费者在item为空的时候检测到count==0,但是这时候被切换走了,去了生产者。生产者发送wakeup,但是丢失了。

/* 定义管程 PC */
monitor PC
{
    int count = 0; 
    /* 我们使用条件变量full 表示被填满的buffer, empty 表示空的buffer */
    conditon full, empty;

    void insert(int item)
    {
        /* 当buffer满的时候,我们在full上将插入操作阻塞 */
        if ( count == MAX ) wait(&full);
        insert_item(item);
        count += 1;
        /* 当buffer不空的时候,我们在empty上唤醒取出操作 */
        if ( count == MAX -1 ) signal(&empty);    
    }

    int remove()
    {
        /* 当buffer空的时候,我们在empty上将取出操作阻塞 */
        if( count == 0 ) wait(&empty);
        remove_item(item);
        count -= 1;
        /* 当buffer不满的时候,我们在full上唤醒插入操作 */
        return item;
        if( count == MAX - 1) signal(&full);
    }
}

void producer()
{
    int item;
    item = produce_item();
    /*调用管程中的函数 */
    PC.insert(item);
}

void consumer()
{
    int item;
    /*调用管程中的函数 */
    item = PC.remove();
    consumer_item();
}

注意 以上代码 用类似于C的代码写成 ,但 C语言并不支持管程。

这样,在insert或者remove的时候就不会被切换走了。

comments powered by Disqus