1,使用信号量解决生产者-消费者问题

首先了解一下信号量吧,信号量是 E.W.Dijkstra 在 1965 年提出的一种方法,它是使用一个整型变量来累计唤醒的次数,供以后使用。在他的建议中,引入了一个新的变量类型,称为信号量(semaphore),一个信号量的取值可以为 0(表示没有保存下来的唤醒操作)或者为正值(表示有一个或多个唤醒操作)。

并且设立了两种操作:down 和 up(分别为一般化后的 sleep 和 wakeup,其实也是一般教科书上说的 P/V 向量)。对一个信号量执行 down 操作,表示检查其值是否大于 0,如果该值大于 0,则将其值减 1(即用掉一个保存的唤醒信号)并继续;如果为 0,则进程休眠,而且此时 down 操作并未结束。另外,就是检查数值,修改变量值以及可能发生的休眠操作都作为单一的,不可分割的 原子操作 来完成。

下面开始考虑用信号量来解决生产者-消费者问题了,不过在此之前,再次分析一下这个问题的本质会更清晰点:问题的实质在于发给一个(尚)未休眠进程(如上的消费者进程在只判断了 count == 0 后即被调度出来,还未休眠)的 wakeup 信号丢失(如上的生产者进程在判断了 count == 1 后以为消费者进程休眠,而唤醒它)了。如果它没有丢失,则一切都会很好。

#define N 100                                // 缓冲区中的槽数目
typedef int semaphore;                // 信号量一般被定义为特殊的整型数据
semaphore mutex = 1;                // 控制对临界区的访问
semaphore empty = N;                // 计数缓冲区中的空槽数目
semaphore full         = 0;                // 计数缓冲区中的满槽数目

/* 生产者进程 */
void proceducer(void)
{
        int item;
       
        while(1)
        {
                item = procedure_item();        // 生成数据
                down(&empty);                                // 将空槽数目减 1
                down(&mutex);                                // 进入临界区
                insert_item(item);                        // 将新数据放入缓冲区
                up(&mutex);                                        // 离开临界区
                up(&full);                                        // 将满槽的数目加 1
        }
}

/* 消费者进程 */
void consumer(voi)
{
        int item;
       
        while(1)
        {
                down(&full);                                // 将满槽数目减 1
                down(&mutex);                                // 进入临界区
                item = remove_item();                // 从缓冲区中取出数据项
                up(&mutex);                                        // 离开临界区
                up(&empty);                                        // 将空槽数目加 1
                consumer_item(item);                // 处理数据项
        }
}

该解决方案使用了三个信号量:一个为 full,用来记录充满的缓冲槽的数目,一个为 empty,记录空的缓冲槽总数,一个为 mutex,用来确保生产者和消费者不会同时访问缓冲区。mutex 的初始值为 1,供两个或者多个进程使用的信号量,保证同一个时刻只有一个进程可以进入临界区,称为二元信号量(binary semaphore)。如果每一个进程在进入临界区前都执行一个 down(...),在刚刚退出临界区时执行一个 up(...),就能够实现互斥。

另外,通常是将 down 和 up 操作作为系统调用来实现,而且 OS 只需要在执行以下操作时暂时禁止全部中断:测试信号量,更新信号量以及在需要时使某个进程休眠。

这里使用了三个信号量,但是它们的目的却不相同,其中 full 和 empty 用来同步(synchronization),而 mutex 用来实现互斥。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/orientalcherry/archive/2008/08/22/2814811.aspx

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值