哲学家就餐问题及其实现
哲学家就餐问题描述
哲学家就餐问题是指,有五个哲学家围坐一桌,每两个哲学家之间都有一只叉子,一共有五只叉子。每个哲学家都只有两个动作,即思考和就餐,哲学家思考的时候不需要任何的资源,但只有同时拿起他左右的两只叉子,才能开始进餐。进餐完毕后将叉子放归原位。这个问题在于,应该如何保证哲学家们的动作有序进行,如不会出现有人永远拿不到叉子的情况。
一些初步的尝试
第一次尝试
对哲学家就餐问题进行分析,可以发现,相邻的两个哲学家对他们中间的叉子应该是互斥访问的。为此,为每个叉子设置一个信号量,每个哲学家在进餐之间,首先需要获得其左右两个叉子,即分别对其左右的两只叉子做一次P
操作;进餐完毕后,将两只叉子放归原位,即分别对其左右两只叉子做一次V
操作。实现的伪代码如下:
Semaphore forks[5];
for(fork : forks)fork.sem = 1; //initialize to 1#define LEFT (i - 1 + 5) % 5
#define RIGHT (i + 1) % 5//for philosopher i
void philosopher(){while(true){thinking();forks[LEFT].P();forks[RIGHT].V();eating();forks[LEFT].V();forks[RIGHT].V();}
}
容易看出,这种实现方法是有问题的,倘若所有五个哲学家同时想要进餐,有一种情况是他们都分别拿起了他们左边的叉子,这样所有哲学家想要获得右边的叉子时都会失败而进入阻塞状态,并且这种阻塞将一直进行下去,因为没有哲学家会主动释放已经获得的叉子,即出现了死锁。
第二次尝试
为了对上面的尝试做出改进,可以注意到,在任意时刻只可能有两个哲学家在同时进餐,因此可以做一些额外的限制,使得只能有两个哲学家同时请求获得叉子,为此可以再设置一个初值为2的信号量mutex
,实现的伪代码如下:
Semaphore forks[5];
for(fork : forks)fork.sem = 1;
Semaphore mutex(2);//for philosopher i
void philosopher(){thinking();//I'm hungrymutex.P();forks[LEFT].P();forks[RIGHT].P();eating();forks[LEFT].V();forks[RIGHT].V();mutex.V();
}
由于任意时刻只能有两个哲学家在请求叉子,因此至少会有一个哲学家可以同时获得他左右的两只叉子然后开始进餐,第一次尝试中死锁的情况在这里不会再发生。但是如果两个请求叉子的哲学家是相邻的,他们中必有一个会进入阻塞状态,此时另外两只叉子还是空闲的,却不能有哲学家进入临界区获得叉子了,也就是说这种策略会导致资源的浪费。
第三次尝试
再次对第一次尝试进行分析,可以发现,第一次尝试之所以会失败,是因为所有哲学家都请求了同一侧的叉子,导致出现了循环等待的情况。为了解决这个问题,可以让不同的哲学家请求不同侧的叉子,比如奇数号的哲学家优先请求左侧叉子,而偶数号的哲学家优先请求右侧叉子。这种策略的伪代码如下:
Semaphore forks[5];
for(fork : forks)fork.sem = 1; //initialize to 1#define LEFT (i - 1 + 5) % 5
#define RIGHT (i + 1) % 5//for philosopher i
void philosopher(){while(true){thinking();if(i % 2 == 1){forks[LEFT].P();forks[RIGHT].V();}else{forks[RIGHT].P();forks[LEFT].P();}eating();forks[LEFT].V();forks[RIGHT].V();}
}
在这种策略下就可以有效避免死锁了,并且还可以实现多人同时就餐,不会有第二次尝试中资源的浪费。
利用AND
信号量实现
AND
信号量我感觉更多是一种思想吧,即在对进程请求的多个资源进行分配时,首先检查这些资源是否都是空闲的,如果的确都是空闲的,则将资源全部分配给该进程,否则一个资源也不分配。很明显,这里检查资源是否空闲过程应该是原子操作才行。我感觉AND
信号量具有多种实现的方法啊,比如可以对资源分配的过程加一个互斥访问锁,如下面的代码指示的那样:
Semaphore mutex(1);void philosopher(){while(true){thinking();//I'm hungrymutex.P();forks[LEFT].P();forks[RIGHT].P();mutex.V();eating();forks[LEFT].V();forks[RIGHT].V();}
}
这里由于把对所有资源的分配组织成了一个原子操作,因此也不会出现第一种尝试中的死锁现象。
另一种方法是把哲学家左右的两只叉子抽象为一个资源,即为每个哲学家设置一个信号量。哲学家请求叉子时,首先检查他相邻的两个哲学家是否在就餐,只有相邻两个哲学家都没有获得叉子的时候才为他分配同时分配两只叉子。应该注意到,检查相邻哲学家是否在就餐,其实就是在检查是否左右两只叉子是否都是空闲状态,因此该检查的动作应该被封装为原子操作。为了检查哲学家的状态,为每个哲学家设置三个状态,即思考THINKING
,饥饿HUNGRY
,和就餐EATING
。实现的伪代码如下:
Semaphore phis[5]; //one semaphore for each philosopher
Semaphore mutex(1);
int state[5];
for(phi : phis)phi.sem = 0; //not available in the beginningvoid check(i){if(state[i] == HUNGRY && (state[LEFT] != EATING && state[RIGHT] != EATING)){state[i] = EATING;phis[i].V(); }
}//for philosopher i
void philosopher(){while(true){thinking();//I'm hungrystate[i] = HUNGRYmutex.P();check(i);mutex.V();phis[i].P();eating();state[i] = THINKING;mutex.P();check(LEFT);check(RIGHT);mutex.V();}
}
在 ucore lab7_report 中还叙述了如何通过条件变量和管程,利用AND
信号量机制来实现哲学家就餐问题。
哲学家就餐问题及其实现相关推荐
- php 哲学家进餐,IPC问题-哲学家就餐(示例代码)
如上图,有五位哲学家,盘中的食物只有左右两个叉子都拿起才能吃.哲学家在桌上只有思考(等待)和吃面(执行).看起来最多是只有2个人能同时吃. 版本一:这个思路的最糟糕的就是都拿起左边叉子,那样都没法吃了 ...
- 哲学家就餐问题c语言_哲学家就餐问题的一种Python解决方案
哲学家就餐问题一直是多线程同步问题的经典案例,本文中展示了多线程竞争共享资源带来的死锁问题,并介绍了一种简单的解决方案. 哲学家就餐问题 哲学家最擅长的就是思考和吃饭 ,当他们感觉累的时候,就会拿起一 ...
- 哲学家就餐问题--信号量和互斥量预防死锁
哲学家就餐问题可以采取预防死锁的方案,就是使用互斥量和信号量锁定资源. 互斥量: 对资源进行锁定的意思就是说,当一个哲学家使用叉子的时候,他首先要先把叉子锁定,然后,拿起来.这个时候如果别的哲学家也来 ...
- 哲学家就餐与死锁问题,死锁产生的条件以及解决方案
请结合经典案例-哲学家就餐,来谈谈你对死锁的理解,以及怎么预防和解除死锁? 哲学家就餐 描述:在一张圆桌上,有n个哲学家,n支筷子,他们的生活方式只是交替地进行思考和进餐,饥饿时便试图取其左.右最靠近 ...
- 哲学家就餐问题php代码,Python实现哲学家就餐问题实例代码
哲学家就餐问题: 哲学家就餐问题是典型的同步问题,该问题描述的是五个哲学家共用一张圆桌,分别坐在五张椅子上,在圆桌上有五个盘子和五个叉子(如下图),他们的生活方式是交替的进行思考和进餐,思考时不能用餐 ...
- 哲学家就餐(避免死锁)(多进程版)
哲学家就餐(避免死锁)(多进程版) 哲学家就餐利用信号量在多进程之间实现 下面展示一些代码片段 #include <stdio.h> #include <unistd.h> # ...
- 哲学家就餐问题(如何避免死锁)(多线程版)
哲学家就餐问题 多线程编程中,常常会遇到线程间访问共享资源的问题,如果处理不当则会发生死锁,某一个线程可能永远访问不到共享资源. 为了避免死锁的发生,提出哲学家就餐问题. 下面展示一些代码片段 #in ...
- 哲学家就餐问题python_Python实现哲学家就餐问题实例代码
哲学家就餐问题: 哲学家就餐问题是典型的同步问题,该问题描述的是五个哲学家共用一张圆桌,分别坐在五张椅子上,在圆桌上有五个盘子和五个叉子(如下图),他们的生活方式是交替的进行思考和进餐,思考时不能用餐 ...
- 哲学家就餐 linux实现_Linux哲学的9个主要原则如何影响您
哲学家就餐 linux实现 上一次,我在Linux哲学的影响中讨论了Linux哲学的较高层次的观点. 关于它有一些非常好的讨论,许多博客联合了Opensource.com. 我从上一篇文章中收到的评论 ...
- Java多线程学习四十二:有哪些解决死锁问题的策略和哲学家就餐问题
线上发生死锁应该怎么办 如果线上环境发生了死锁,那么其实不良后果就已经造成了,修复死锁的最好时机在于"防患于未然",而不是事后补救.就好比发生火灾时,一旦着了大火,想要不造成损失去 ...
最新文章
- 视频聊天创企Tribe获300万美元种子轮融资
- java中抽象类 接口_java中的抽象类与接口
- POJ3041Asteroids(二分图最少顶点覆盖)
- ITK:使用二项式内核模糊图像
- MQ消息队列产品测试
- 时间序列分析 lstm_LSTM —时间序列分析
- pytorch中获取指定位置元素
- 真机调试时部分日志丢失(魅族)
- Mybatis源码解析:sql参数处理(2)
- [转]史上最全最强SpringMVC详细示例实战教程
- java判断字符串是子串_【Java】判断字符串是否包含子字符串
- 小米高管:已投大量精力研发手机AI芯片,造不造还没定
- ubuntu16.04中将自己的ubuntu做成镜像
- 程序员的终极幻想(一):像操作数据库那样操作大脑的记忆
- 两个运放制作加法器_初级模拟电路:8-2 加法与减法电路
- Linux设备模型分析之bus
- 一起捉妖服务器还要维护多久,一起来捉妖:在线6小时被劝退?只需网络断开,跳过等待15分钟...
- 如何手工删除oracle数据库和软件
- 员工修改添加,部门修改添加
- web端生成pdf,前端生成pdf导出并自定义页眉页脚
热门文章
- 怎么使用USB Redirector远程共享软件加密狗
- [AHOI2007]密码箱
- 桂林理工大学 就业指导 2021 创业项目计划书样本
- 为什么选择Mapabc
- c++基础--另类的分支结构
- 带你揭秘网络工程师群体!
- mac配置VMware Fusion虚拟机网络配置
- hbase版本对应的hadoop版本
- java opencv 纠偏_一种基于OpenCV的高拍仪拍摄文档物体纠偏方法与流程
- 计算机环境怎么安装包,win10游戏运行环境包怎么安装_win10电脑游戏运行环境包安装详细步骤...