
生产者-消费者问题从特殊到一般(从易到难)可以分3种形式:
一个生产者、一个消费者、一个缓冲区的问题;
一个生产者、一个消费者、n个缓冲区的问题;
k个生产者、m个消费者、n个缓冲区的问题;
★当缓冲区空时,生产者可将产品存入缓冲区;当缓冲区满时,生产者必须等待 (阻塞),待消费者取走产品后将其唤醒后,才能将产品存入。
1. 为生产者设置 1 个私有信号量 empty ,其初值为 1 ,表示有 1 个空缓冲区;为消费者设置 1 个私有信号量 full ,其初值为 0 ,表示开始时没有满缓冲区;( 信号量初值由物理意义确定 )2. 生产者将产品存入缓冲区之前,应先 测试 缓冲区是否空:执行 wait(empty) 操作;离开临界区 ( 存入产品 ) 后,应 通知 ( 可能会唤醒 ) 消费者:执行 signal(full) 操作;3. 消费者从缓冲区取产品之前,应先 测试 缓冲区是否满:执行 wait(full) 操作;离开临界区 ( 取走产品 ) 后,应 通知 ( 可能会唤醒 ) 生产者:执行 signal(empty) 操作
生产者消费者问题的算法描述如下所示:
初始化设置
- semaphore empty,full;
- empty=1;full=0;
生产者
- parbegin
- process Producer:
- {
- produce an item in nextp;
- wait(empty);//测试
- buffer=nextp;
- signal(full);//通知消费者
- }
消费者
- process Consumer:
- {
- wait(full); //测试
- nextc=buffer;
- signal(empty); //通知
- consume the item
- in nextc;
- }
- parend
信号量机制解决进程同步问题的一般方法:
为生产者设置一个资源信号量empty ,其初值为生产者的可用资源数 ( 空缓冲区的个数 )n ,即 empty=n 。为消费者设置一个资源信号量full ,其初值为消费者的可用资源数 ( 满缓冲区的个数 )0 ,即 full=0 。
生产者消费者问题的算法描述如下所示:
初始化设置
- semaphore empty,full;
- empty=n;full=0;
- int in=0,out=0; //下标
生产者
- parbegin
- process Producer:
- {
- produce an item in nextp;
- wait(empty);//测试
- buffer[in]=nextp;
- in=(in+1)%n;
- signal(full);//通知消费者
- }
消费者
- process Consumer:
- {
- wait(full); //测试
- nextc=buffer[out];
- out=(out+1)%n;
- signal(empty); //通知
- consume the item in nextc;
- }
- parend
本题中in和out不是共享变量(因为只有一个生产者和一个消费者),无需互斥访问。

初始化
- semaphore mutex,empty,full ;
- item buffer[n] ;
- int in = 0,out = 0 ;
- mutex.value = 1;
- empty.value=n,full.value=0;
生产者
- parbegin //并发执行开始
- process produceri (i=1,2,…,k) //生产者进程
- {
- item nextp;
- while (true)
- {
- produce an item nextp;
- wait(empty) ; //测试是否有可用的资源
- wait(mutex); //互斥(进入临界区)
- buffer[in] = nextp ;
- in = (in + 1)% n ;
- signal(mutex) ; //退出临界区
- signal(full) ; //通知(可能唤醒)协作方
- }
- }
消费者
- process consumerj (j=1,2,…,m)
- { item nextc ;
- while (true) {
- wait(full); //测试是否有可用的资源
- wait(mutex);
- nextc = buffer[out] ;
- out = (out + 1)% n ;
- signal(mutex);//生产者消费者互斥访问缓冲区,同时生产者互斥生产,消费者户次消费
- signal(empty); //通知(可能唤醒)协作方
- consume the item in nextc ;
- }
- }
- parend //并发执行结束