操作系统-同步机制

你好!这里是风筝的博客,

欢迎和我一起交流。


说到同步,不得不说著名的生产者-消费者问题(producer-consumer problem),解决好生产者-消费者问题,就解决了并发进程的同步问题。

“生产者-消费者”问题描述如下:
有一个有限缓冲区和多个消费者和生产者,它们分别不停地把产品放入缓冲区中拿走产品。一个生产者在缓冲区满的时候必须等待,一个消费者在缓冲区空的时候也必须待。

int k;                          /*缓存区大小*/
item buffer[k];                 /*缓存区*/
int counter=0,in=0,out=0;

//生产者进程
process producer(void)
{
    while (true)
    {
        produce an item in nextp;/*生产一个产品*/
        if (counter==k)         /*缓冲满时*/
            sleep(producer);    /*生产者睡眠*/
        buffer[in]=nextp;       /*将一个产品放入缓冲区*/
        in=(in+1) mod k;        /*指针推进*/
        counter++;              /*缓冲内产品数加1*/
        if (counter==1)         /*缓冲之前为空*/
            wakeup(consumer);   /*加进一件产品并唤醒消费者*/
    }
}

//消费者进程
process consumer(void)
{
    while (true)
    {
        if (counter==0)         /*缓冲为空*/
            sleep (consumer);   /*消费者睡眠*/
        nextc=buffer[out];      /*取一个产品到nextc*/
        out=(out+1) mod k;      /*指针推进*/
        counter--;              /*缓冲内产品数减1*/
        if (counter==k-1)       /*缓冲之前为满*/
            wakeup(producer);   /*取走一件产品并唤醒生产者*/
        consume the item in nextc;/*消费一个产品*/
    }
}

上面的程序,两组进程顺序执行是没问题的,但是若并发执行,就会出现错误结果,出错的根子在于进程之间共享了变量counter,对counter 的访问未加限制。生产者和消费者进程对counter 的交替执行会使其结果不唯一。例如生产者执行counter++后进程切换到消费者,消费者里又对counter–操作,显然是不对的。
更为严重的是生产者和消费者进程的交替执行会造成系统死锁。
假定消费者读取counter 发现它为0。此时调度程序切换到生产者,生产者加入一个产品,将counter 加1,现在counter 等于1 了。它想当然地推想由于counter刚刚为0,所以,此时消费者一定在睡眠,于是生产者调用wakeup 来唤醒消费者。不幸的是,消费者还未去睡觉,唤醒信号被丢失掉。当消费者再次运行时,因已测到counter为0,于是去睡眠。这样生产者迟早会填满缓冲区,然后,去睡觉,形成了进程都永远处于睡眠状态。
这次是因为它们访问缓冲区的速率不匹配造成的,需要调整并发进程的进行速度。并发进程间的这种制约关系称进程同步,交互的并发进程之间通过交换信号或消息来达到调整相互速率,保证进程协调运行的目的。

1965年,一位荷兰的大佬就提出了一个同步工具:信号量和PV操作。
P(semaphore):将信号量的值减一,若结果小于零,则执行P操作的进程被阻塞,进入等待队列中;若结果大于等于零,则执行P操作的进程继续执行。
V(semaphore):将信号量的值加一,若结果小于等于零,则执行V操作的进程唤醒队列中的一个等待进程,自己则继续执行;若结果大于零,则执行V操作的进程继续执行。

利用信号量即可解决并发进程的竞争问题,又可解决并发进程的协作问题。

semaphore empty =1;
semaphore full=0;
item buffer[1];                 /*缓存区*/
int in=0,out=0;

process producer(void)
{
    while (true)
    {
        produce an item in nextp;/*生产一个产品*/
        P(empty);
        buffer[0]=nextp;        /*将一个产品放入缓冲区*/
        V(full);
    }
}

process consumer(void)
{
    while (true)
    {
        P(full);
        nextc=buffer[0];        /*取一个产品到nextc*/
        V(empty);
        consume the item in nextc;/*消费一个产品*/
    }
}

这样就很好的解决了消费者-生产者问题,但是,这个程序的模型是一个生产者(semaphore empty =1),如果有k个生产者呢?

int k;                          /*缓存区大小*/
semaphore empty =k;
semaphore full=0;
semaphore mutex=1;
item buffer[k];                 /*缓存区*/
int in=0,out=0;

process producer(void)
{
    while (true)
    {
        produce an item in nextp;/*生产一个产品*/
        P(empty);
        P(mutex);
        buffer[in]=nextp;       /*将一个产品放入缓冲区*/
        in=(in+1) mod k;        /*指针推进*/
        V(mutex);
        V(full);
    }
}

process consumer(void)
{
    while (true)
    {
        P(full);
        P(mutex);
        nextc=buffer[out];      /*取一个产品到nextc*/
        out=(out+1) mod k;      /*指针推进*/
        V(mutex);
        V(empty);
        consume the item in nextc;/*消费一个产品*/
    }
}

这样,只需要把资源(产品)再用一组PV操作保护起来就好了。

猜你喜欢

转载自blog.csdn.net/guet_kite/article/details/78752479