生产者 - 消费者问题
问题描述
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
记录型信号量
思路
- 假定在生产者和消费者之间的公用缓冲池中具有n个缓冲区,这时可利用互斥信号量mutex实现诸进程对缓冲池的互斥使用;利用信号量empty和full分别表示缓冲池中空缓冲区和满缓冲区的数量。又假定这些生产者和消费者相互等效,只要缓冲池未满,生产者便可将消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中取走一个消息。
- 使用互斥信号量mutex,实现对公用缓冲池的互斥使用
- 使用信号量empty和full代替原来的count计数,同时实现线程的同步机制
- 利用数组buffer模拟具有n个缓冲区的缓冲池,指针in,out表示该放入缓冲区的位置,于该取走缓冲区的位置,使用 ( in / out = (in / out + 1) % n)实现循环缓冲区
代码实现
int in = 0, out = 0; //位置记录 item buffer[n]; //缓冲池 semaphore mutex = 1; //互斥信号量 semaphore empty = n, full = 0; //同步信号量 void producer(){ do{ produce an item nextp; //产生商品nextp …… wait(empty); //wait的顺序不能变换 wait(mutex); buffer[in] = nextp; in = (in + 1) % n; signal(mutex); signal(full); }while(TRUE); } void consumer(){ do{ wait(full); //wait的顺序不能变换 wait(mutex); nextc = buffer[out]; out = (out + 1) % n; signal(mutex); signal(empty); consumer the item in nextc; …… }while(TRUE); } void main(){ cobegin; //同时开始 producer(); consumer(); coend; }
注意点
- 互斥型信号量mutex的wait()与signal()操作一定要成对出现
- 资源信号量empty与full的wait()与signal操作虽然不在同一进程中,但是为了实现同步,同时避免死锁一定也要对应出现
- 一个进程中的wait()操作的次序不能颠倒,一定是先对资源信号量再对互斥信号量使用wait()
AND信号量
思路
- 因为同时需要生产者与消费者都同时需要两个信号量的控制,故引入AND信号量
- 使用Swait(empty,mutex)代替wait(empty),wait(mutex)
- 使用Ssignal(mutex, full)代替signal(mutex),signal(full)
- 同理Swait(full,mutex),Ssignal(mutex, empty)
代码实现
int in = 0, out = 0; //位置记录 item buffer[n]; //缓冲池 semaphore mutex = 1; //互斥信号量 semaphore empty = n, full = 0; //同步信号量 void producer(){ do{ produce an item nextp; …… Swait(empty, mutex); buffer[in] = nextp; in = (in + 1) % n; Ssignal(mutex, full); }while(TRUE); } void consumer(){ do{ Swait(full, mutex); nextc = buffer[out]; out = (out + 1) % n; Ssignal(mutex, empty); consumer the item in nextc; …… }while(TRUE); } void main(){ cobegin; //同时开始 producer(); consumer(); coend; }