经典同步问题
生产者-消费者问题
二者共享一个有界缓冲区,生产者向其中生产产品,消费者从中取出产品。
此过程中设置两个同步信号量,empty表示空缓冲区数量,其初值为N,full表示满缓冲区数量,初值为0,此外还要设置一个互斥信号量mutex,初值为1,来保证多个生产者或者多个消费者互斥地访问缓冲池。
分析条件:
- 有产品的情况下才能消费,full变量来控制;
- 缓冲区数量有限,不能无限生产,用empty来控制
- 同类进程互斥访问,mutex实现
full = 0;
empty = 0;
mutex = 1;
Pruducer(){
wait(empty);//申请空缓冲区,自动更新空缓冲区数量
wait(mutex);//申请访问缓冲区权限
singal(mutex);//释放访问缓冲区权限
singal(full);//更新满缓冲区数量,增加一个满缓冲区
}
Consumer(){
wait(full);//申请空缓冲区,自动更新空缓冲区数量
wait(mutex);//申请访问缓冲区权限
singal(mutex);//释放访问缓冲区权限
singal(empty);//更新满缓冲区数量,增加一个k空缓冲区
}
注意:
执行顺序不可颠倒,必须先进行对资源信号量的P操作,然后才能进行互斥信号量的P操作,否则可能导致死锁。
读写者问题
分析条件:
- 任意多个读者可以同时读这个数据区
- 同时只能有一个写者可以写这个数据区
- 如果一个写者正在写这个数据区,禁止任何读者和写者访问该数据区。
需要考虑问题:读者优先,公平情况,写者优先
读者优先
读者优先也就是若有读者在读,新来读者可以立马读,而写者必须等待所有读者全部读完才能写
readCount = 0;
wmutex = 1;
rmutex = 1;
Reader(){
wait(rmutex);//申请readCount的使用权
if(readCount==0){
wait(wmutex);//阻止写者写数据
}
readCount++;//更新读者数量
singal(rmutex);//释放使用权
wait(rmutex);//申请readCount的使用权
readCount--;//更新读者数量
if(readCount==0){
singal(wmutex);//允许写者写数据
}
singal(rmutex);//释放使用权
}
Writer(){
wait(wmutex);//申请readCount的使用权
singal(wmutex);//释放使用权
}
哲学家进餐问题
分析条件:
五个哲学圆桌而围,每个人只有一根筷子,如何解决进餐问题。
我们规定大家逆时针围桌而坐,0号哲学家的左手筷子为0号筷子,右边边筷子是1号筷子,以此类推。
sm = 4;
fork[5]={
1,1,1,1,1};//5筷子是否被用
philosopher(int i){
wait(fork[i%5]);//拿起左手筷子
wait(fork[(i+1)%5]);//拿起右手筷子
singal(fork[i%5]);//放下左手筷子
singal(fork[(i+1)%5]);//放下右手筷子
}
以上过程可能造成死锁
sm = 4;
fork[5]={
1,1,1,1,1};//5筷子是否被用
philosopher(int i){
wait(sm);
wait(fork[i%5]);//拿起左手筷子
wait(fork[(i+1)%5]);//拿起右手筷子
singal(fork[i%5]);//放下左手筷子
singal(fork[(i+1)%5]);//放下右手筷子
singal(sm);
}
或者
fork[5]={
1,1,1,1,1};//5筷子是否被用
philosopher(int i){
if(i%2!=0){
wait(fork[i%5]);//拿起左手筷子
wait(fork[(i+1)%5]);//拿起右手筷子
singal(fork[i%5]);//放下左手筷子
singal(fork[(i+1)%5]);//放下右手筷子
}
else{
wait(fork[(i+1)%5]);//拿起右手筷子
wait(fork[i%5]);//拿起左手筷子
singal(fork[(i+1)%5]);//放下右手筷子
singal(fork[i%5]);//放下左手筷子
}
}
管程机制
管程定义了一个数据结构和能为并发进程所执行的一组操作,这组操作能同步进程和改变管程中的数据,管程构成的三部分:
- 局部对于管程的贡献数据结构说明
- 操作这些数据结构的一组过程
- 对于局部与管程的数据设置初始值语句