2.5 经典的进程同步问题(重点!!!)
- 一、生产者-消费者问题
- 二、哲学家进餐问题
- 三、读者-写者问题
一、生产者-消费者问题
有几个进程?
存在什么模式?
对于生产者-消费者问题,存在两个进程,分别是生产者进程和消费者进程
buffer是生产者和消费者两个进程共享的公共资源,属于临界资源,所以是互斥方式共享buffer。
1、利用记录型信号量解决生产者-消费者问题
可利用互斥信号量mutex实现诸进程对缓冲池的互斥使用;
利用信号量empty和full分别表示缓冲池中空缓冲池和满缓冲池的数量
程序实现
对于producer程序而言,wait(empty)看缓冲区是否还有存储空间,wait(mutex)则是用来申请缓冲区资源
对于consumer程序而言,wait(full)看缓冲区中时候有商品,wait(mutex)则是用来申请缓冲区资源
当缓冲区是满的时候,empty为0,full为n。此时若先执行wait(mutex),再执行wait(empty),会造成生产者申请到缓冲区资源,但是缓冲区没有存储空间来存储商品;而对于消费者进程而言,若先执行wait(mutex),再执行wait(full),那么会导致,消费者申请不到缓冲区资源,此时即使缓冲区有商品,依然无法将商品取出消费。陷入死锁。
生产者在等消费者去消费,消费者在等生产者释放mutex。(死锁的情况)
退出区释放资源的时候没有顺序要求!
2、利用AND型信号量解决生产者-消费者问题
一次性的申请和释放资源型信号量和互斥信号量。
二、哲学家进餐问题
1、利用记录型信号量解决哲学家进餐问题
程序实现
该算法虽然可以保证相邻两人不会同时进餐,但是有可能引起死锁。
因为当五个人同时饿了的时候,大家都会拿起自己左手边的一个筷子,这时每个人只有一只筷子没法进餐,因此也没法释放资源,于是五个人只能等着饿死,陷入死锁。
解决方法:
- 方法1:至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用完后释放出他用过的两只筷子,从而使更多的哲学家能够进餐。
- 方法2:仅当哲学家的左右两支筷子均可用时,才允许他拿起筷子进餐。
- 方法3:规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;偶数号哲学家则相反。
方法1:程序实现
筷子是互斥信号量组
饥饿的哲学家的人数为资源信号量
方法2:利用AND型信号量机制解决哲学家进餐问题
在哲学家进餐问题中,要求每个哲学家先获得两个临界资源(筷子)后方能进餐。本质上是AND同步问题。
方法3:程序实现:
三、读者-写者问题
1、利用记录型信号量解决读者-写者问题
- 互斥信号量wmutex:实现reader与writer进程间在读或写时的互斥,整型变量readcount:表示正在读的进程数目;
- 由于只要有一个reader进程在读,便不允许writer进程写。所以,仅当readcount=0,即无reader进程在读时,reader才需要执行wait操作。若wait(wmutex)操作成功,reader进程便可去读,相应地,做readcount+1操作。
- 同理,仅当reader进程在执行了readcount减1操作后其值为0时,才需执行signal(wmutex)操作,以便让write进程写。
互斥信号量rmutex:reader进程间互斥访问readcount。
对于reader进程:
- 1、先申请readcount资源,即执行wait(rmutex)
- 2、如果readcount=0,则需要再申请wmutex,即执行wait(wmutex),然后执行readcount+1,接着释放readcount资源,即执行signal(rmutex)。
- 3、如果readcount!=0,则直接执行readcount+1,然后释放readcount资源,即执行signal(rmutex)。
- 4、执行读操作
- 5、申请readcount资源,执行readcount-1
- 6、如果readcount=0,那么释放wmutex,即执行signal(wmutex),否则直接释放rmutex,即执行signal(rmutex)。
写进程就是正常的申请wmutex资源,然后执行写操作,释放wmutex,即执行signal(wmutex)。
2、利用信号量集机制解决读者-写者问题
对于reader进程和writer进程:
- 每来一个读进程,会是L-1,最多可以使RN个读进程来申请资源
- swait(mx,1,0)语句起着开关的作用。只要无writer进程进入写,mx=1,reader进程就都可以进入读。但只要一旦有writer进程进入写时,mx=0,则任何reader进程就都无法进入读。
- swait(mx, 1, 1; L, RN, 0)语句表示仅当既无writer进程在写(mx=1),又无reader进程在读(L=RN),writer进程才能进入临界区写。