抽象程度比信号量更高。
目的:分离互斥和条件同步的关注
什么是管程:
一个锁:指定临界区;0或者多个条件变量:等待/通知信号量用于管理并发访问共享数据。
一般方法:
收集在对象/模块中的相关共享数据;定义方法来访问共享数据。
Lock
Lock::Acquire() - 等待知道锁可用,然后抢占锁
Lock::Release() - 释放锁,唤醒等待者如果有的话
Condition Variable
允许等待状态进入临界区:允许处于等待(睡眠)的线程进入临界区;某个时刻原子释放锁进入睡眠
Wait() operation: 释放锁,睡眠,重新获得锁返回后
Signal() operation (or broadcast() operation ):唤醒等待者(或者所有等待者),如果有
条件变量实现:
需要维护每个条件队列;线程等待的条件等待signal()
class Condition{
int numWaiting = 0;
WaitQueue q;
}
Condition::Wait(lock){
numWaiting++;
Add this thread t to q;
release(lock);
schedule();//need mutex
require(lock);
}
Condition::Signal(){
if(numWaiting > 0){
Remove a thread t from q;
wakeup(t)://need mutex
numWaiting--;
}
}
numWaiting当前等待队列中的个数。注意在scedule之前释放锁的操作。
用管程解决 生产者-消费者问题
class BoundedBuffer{
...
Lock lock;
int count = 0;
Condition notFull,notEmpty;
}
BoundedBuffer::Deposit(c){
lock->Acquire();
while(count == n)
notFull.Wait(&lock);//这个lock就是之前说的事先释放的锁
Add c to the buffer;
count++;
notEmpty.Signal();
lock->Release();
}
BoundeBuffer::Remove(c){
lock->Acquire();
while(count == 0)
notEmpty.Wait(&lock);
Remove c from buffer;
count--;
notFull.Signal();
lock->Release();
}
只能一个线程进入管程,所以在头尾有 锁 包起来,实现互斥。