问题描述
问题分析
- 任何时刻只能有一个线程操作缓冲区(互斥访问)
- 缓冲区为空时,消费者必须等待生产者(条件同步)
- 缓冲区为满时,生产者必须等待消费者(条件同步)
用信号量描述每个约束
- 二进制信号量mutex
- 资源信号量fullBuffers
- 资源信号量emptyBuffers
具体实现:
class BoundedBuffer{
mutex = new Semaphore(1);
fullBuffers = new Semaphore(0);
emptyBuffers = new Semaphore(n);
}
BoundedBuffer::Deposit(c){
//缓冲区空间减一
emptyBuffers->P();
//进入互斥访问
mutex->P();
Add c to the buffer;
mutex->V();
//离开临界区
//生产资源加一
fullBuffers->V();
}
BoundedBuffer::Remove(c){
//生产资源减一
fullBuffers->P();
mutex->P();
Remove c from buffer;
mutex->V();
//缓冲区空间加一
emptyBuffers->V();
}
使用信号量的困难
- 读/开发代码比较困难:程序员需要能运用信号量机制
- 容易出错
a. 使用的信号量已经被另一个线程占用
b. 忘记释放信号量
使用管程实现:
class BoundedBuffer{
Lock lock;
int count = 0; //表示当前buffer的资源
Condition notFull,notEmpty; //两个条件变量
}
BoundedBuffer::Deposit(c){
lock->Acquire();
//若缓存区满时,则放弃管程访问
while(count == n){
notFull.Wait(&lock);
}
Add c to the buffer;
count ++;
//唤醒等待的消费者
notEmpty.Signal();
lock->Release();
}
BoundedBuffer::Remove(c){
lock->Acquire();
//若生产资源为空时,放弃管程访问
while(count == 0){
notEmpty.Wait(&lock);
}
Remove c from buffer;
count --;
//唤醒等待的生产者
notFull.Signal();
lock->Release();
}
管程操作可以将PV操作放在一个模块中,可以简化PV操作。