操作系统-同步机制

来源:互联网 发布:下载会计软件多少钱 编辑:程序博客网 时间:2024/05/22 06:22

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

欢迎和我一起交流。


说到同步,不得不说著名的生产者-消费者问题(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操作保护起来就好了。

原创粉丝点击