
生产者-消费者问题从特殊到一般(从易到难)可以分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 itemin nextc;
}
parend
信号量机制解决进程同步问题的一般方法:
1. 为同步双方设置各自的信号量,初值为其初始状态可用的资源数 ( 故该信号量称为 资源信号量 或 私有信号量 ) ;
2. 同步双方任一进程在进入临界区之前,应先对自己的信号量执行 wait(< 己方信号量 >) 操作,以 测试 是否有自己可用的资源。若有资源可用,则进入临界区,否则阻塞;
3.同步双方任一进程离开临界区后,应对合作方 (对方)的信号量执行signal(<对方信号量>)操作,以通知(若对方处于阻塞状态,则唤醒它)对方已有资源可用(对方已可进入临界区)。
一个生产者、一个消费者、n个缓冲区
为生产者设置一个资源信号量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不是共享变量(因为只有一个生产者和一个消费者),无需互斥访问。
K个生产者、M个消费者、n个缓冲区

1、设置生产者的资源信号量 empty ,其初值为 n ,表示开始时有 n 个空缓冲区;
2、设置消费者的资源信号量 full ,其初值为 0 ,表示开始时有 0 个满缓冲区;
3、只要有空的缓冲区,生产者便可将消息送入缓冲区;
4、只要有满的缓冲区,消费者便可从缓冲区取走一个消息。
5、用互斥信号量 mutex 对缓冲区 ( 共享变量 in 和 out) 的互斥使用,互斥信号量 mutex 初值为 1 ;
6、生产者用共享变量 in 作为下标访问缓冲区, mutex 为其互斥信号量;消费者用共享变量 out 作为下标访问缓冲区,其互斥信号量也用 mutex 。
初始化
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 //并发执行结束
注意:
在每个进程中,实现互斥的 wait(mutex) 和 signal(mutex) 必须成对出现;
对资源信号量 empty和full 的 wait 和 signal 操作也要成对地出现,但它们处于不同的进程中 ( 交叉成对 ) 。
在每个进程中的多个 wait 操作顺序不能颠倒,应先执行对资源信号量(也称私有信号量)的 wait 操作,然后执行对互斥信号量(公有信号量)的 wait 操作,否则可能引起进程死锁。
重申信号量解决同步问题的要点:
1. 为同步双方设置各自的信号量,初值为其初始状态可用的资源数 ( 故该信号量称为 资源信号量 或 私有信号量 ) ;
2. 同步双方任一进程在进入临界区之前,应先对自己的资源信号量执行 wait(< 己方信号量 >) 操作,以 测试 是否有自己可用的资源。若有资源可用,则进入临界区,否则阻塞;
3. 同步双方任一进程离开临界区后,应对合作方 ( 对方 ) 的资源信号量执行 signal(< 对方信号量 >) 操作,以 通知 ( 若对方处于阻塞状态,则唤醒它 ) 对方已有资源可用 ( 对方已可进入临界区 ) 。


















