生产者消费者问题是操作系统中非常重要的知识点。
其思想就是生产者和消费者公用一个缓冲区,生产者生产产品放入缓冲区,消费者从缓冲区取出产品,当缓冲区满,那么生产者阻塞,当缓冲区空,消费者阻塞,同时二者在放入和取出时应当独占缓冲区,即不允许对方操作缓冲区以保证同步。
在这类问题当中,一般至少需要维持三个变量:
- 空余位置大小
- 已占位置大小
- 互斥锁
用代码实现
var items = 0, space = 10, mutex = 1;
item buf[n];
producer {
while( true ) {
wait( space ); // 等待缓冲区有空闲位置, 在使用PV操作时,条件变量需要在互斥锁之前
wait( mutex ); // 保证在product时不会有其他线程访问缓冲区
buf.push(item);
signal( mutex ); // 唤醒的顺序可以不同
signal( items ); // 通知consumer缓冲区有资源可以取走
}
}
consumer {
while( true ) {
wait( items ); // 等待缓冲区有资源可以使用
wait( mutex ); // 保证在consume时不会有其他线程访问缓冲区
buf.pop(); // 将buf[out]位置的的资源取走
signal( mutex ); // 唤醒的顺序可以不同
signal( space ); // 通知缓冲区有空闲位置
}
}
例题:
桌子上只有一个盘子,每次只能向其中放入一个水果,爸爸只放苹果,女儿只吃苹果,妈妈只放橘子,儿子只吃橘子。只有盘子空时,妈妈或爸爸才可放一个水果;当盘子有自己需要的水果时,儿子或女儿才可以从盘子中取出。
semaphore plate=1,apple=0,orange=0;
dad()
{
while(1)
{
wait(plate);
put an apple;
signal(apple);
}
}
mom()
{
while(1)
{
wait(plate);
put an orange;
signal(orange);
}
}
daughter()
{
while(1)
{
wait(orange);
take an orange;
signal(plate);
}
}
son()
{
while(1)
{
wait(apple);
take an apple;
signal(plate);
}
}