信号量解决哲学家吃饭问题
问题介绍
前提假设:
一个哲学家吃饭要同时用到左右两个叉子;
哲学家的行为有:吃、思考。
要求:
合理的安排大家就餐。
最初级的方案
用一组p()\v()信号量 来实现哲学家吃饭的互斥。
1 | semaphore mutex |
分析:
每个哲学家互斥了,但是每次只允许一个人进餐。而理论上,5个人,可以同时2人吃饭。把就餐人员看成了“必须互斥的临界资源”(而不是叉子),造成了(叉子)资源的浪费。下面改进方案其实就是用一个 “状态”来代替哲学家作为临界资源,而“状态”是包括【哲学家、叉子】信息组合而成的集合体,包括了叉子资源,因此减少了叉子资源的浪费。
改进方案
基本思想:
要么不拿,要么拿左右2个叉子。
不浪费CPU时间,进程间相互通信,让5个进程并发执行。
步骤:
s1 思考
s2 进入饥饿
s3 如果左右邻居都在进餐,进程进入阻塞状态,否则 s4。
s4 拿起左右两个叉子
s5 eating
s6 放下左边的叉子,看看左边的邻居能否就餐,若能就唤醒
s7 放下右边的叉子,看看右边的邻居能否就餐,若能就唤醒
s8 回到 s1
程序设计:
1、因为哲学家有吃和思考两种行为,而吃有约束条件思考没有,所以哲学家一定有3种状态——吃、饥饿、思考。
2、用数据结构描述哲学家当前状态。
3、把 状态 视为临界资源,哲学家对它的访问需要 ”互斥“ 。
4、一个人吃饱后,需要唤醒其左右他人,相邻的人之间存在 ”同步” 关系。
1 | N = 5 //5个哲学家 |
1 | void philosopher(int i) |
1 | void take_forks(int i) //第i个哲学家 |
1 | void test_take_left_right_forks(int i) |
1 | void put_forks(int i) |
1 | void think(int i) |
以上用信号量实现了5个进程并发执行,可以2个进程一起执行。不会死锁。