操作系统: 生产者-消费者问题
1、单生产者和单消费者
缓存绑定问题,两个进程:生产者和消费者,一个固定大小的缓存。
生产者的工作就是制造一段数据,放进缓存,如此反复;
消费者则一次消费一段数据(将其从缓存中移除),
问题的核心: 就是要保证不让生产者在缓存还是满的时候仍要向缓存写数据,
不让消费者试图从空的缓存中取出数据。
该问题需要注意的几点:
- 在缓冲区为空时,消费者不能再进行消费
- 在缓冲区为满时,生产者不能再进行生产
- 在一个线程进行生产或消费时,其余线程不能再进行生产或消费等操作,即保持线程间的同步
- 注意条件变量与互斥锁的顺序
伪代码实现
假设缓冲区大小为10,生产者、消费者线程若干。
生产者和消费者相互等效,只要缓冲池未满,生产者便可将消息送入缓冲池;
只要缓冲池未空,消费者便可从缓冲池中取走一个消息。
items 代表缓冲区已经使用的资源数,spaces代表缓冲区可用资源数
mutex 代表互斥锁
buf[10] 代表缓冲区,其内容类型为item
in、out 代表第一个资源和最后一个资源
var items = 0, space = 10, mutex = 1;
var in = 0, out = 0;
item buf[10] = { NULL };
producer {
while( true ) {
wait( space ); // 等待缓冲区有空闲位置, 在使用PV操作时,条件变量需要在互斥锁之前
wait( mutex ); // 保证在product时不会有其他线程访问缓冲区
// product
buf.push( item, in ); // 将新资源放到buf[in]位置
in = ( in + 1 ) % 10;
signal( mutex ); // 唤醒的顺序可以不同
signal( items ); // 通知consumer缓冲区有资源可以取走
}
}
consumer {
while( true ) {
wait( items ); // 等待缓冲区有资源可以使用
wait( mutex ); // 保证在consume时不会有其他线程访问缓冲区
// consume
buf.pop( out ); // 将buf[out]位置的的资源取走
out = ( out + 1 ) % 10;
signal( mutex ); // 唤醒的顺序可以不同
signal( space ); // 通知缓冲区有空闲位置
}
}