​ 本文和接下来几篇博文是对上篇文章(进程同步机制)的一次实践,通过具体的例子来加深理论的理解,会用三个经典的进程同步问题来进行讲解,并且会配有伪代码和Java实践(使用多线程模拟),深入的进行讲解。

​ 进程同步问题是一个非常重要且相当有趣的问题,本文我们对其中比较有名的哲学家进餐问题来进行探讨。哲学家进餐问题是诸进程间竞争临界资源而导致死锁的典型例子,具有很大的代表性,因此在这里我们也对其进行一些分析。

​ 值得一提的是,哲学家进餐问题又双叒叕是我们的老熟人迪杰斯特拉提出并解决的,让我们一起来看下吧。

1.问题描述

​ 有五个哲学家围在一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和物质筷子,他们的生活方式是交替的进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕后,放下筷子继续思考。

​ 我们可以从上面的题目中得出,筷子是临界资源,同一根筷子同一时刻只能有一个哲学家可以拿到。

2.问题分析

​ 由问题描述我们可以知道,一共有五个哲学家,也就是五个进程;五只筷子,也就是五个临界资源;因为哲学家想要进餐,必须要同时获得左边和右边的筷子,这就是要同时进入两个临界区(使用临界资源),才可以进餐。

## 3.信号量设置

​ 因为是五只筷子为临界资源,因此设置五个信号量即可。

4.一个错误例子

​ 首先我们根据我们之前学习的知识来解决问题,根据上面的分析,我们先给出伪代码:

semaphore mutex[5] = {1,1,1,1,1};       //初始化信号量void philosopher(int i){do {//thinking          //思考P(mutex[i]);//判断哲学家左边的筷子是否可用P(mutex[(i+1)%5]);//判断哲学家右边的筷子是否可用//...//eat       //进餐//...V(mutex[i]);//退出临界区,允许别的进程操作缓冲池V(mutex[(i+1)%5]);//缓冲池中非空的缓冲区数量加1,可以唤醒等待的消费者进程}while(true);
}

​ 我们来分析下上面的代码,首先我们从一个哲学家的角度来看问题,程序似乎是没有问题的,申请到左右两支筷子后,然后开始进餐。但是如果考虑到并发问题,五个哲学家同时拿起了左边的筷子,此时,五只筷子立刻都被占用了,没有可用的筷子了,当所有的哲学家再想拿起右边筷子的时候,因为临界资源不足,只能将自身阻塞,而所有的哲学家全部都会阻塞,并且不会释放自己手中拿着的左边的筷子,因此就会一直处于阻塞状态,无法进行进餐并思考。

​ 因为,为了解决五个哲学家争用的资源的问题,我们可以采用以下几种解决方法:

  1. 至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用餐完毕后能释放他占用的筷子,从而使别的哲学家能够进餐;
  2. 仅当哲学家的左、右两支筷子可用时,才允许他拿起筷子;
  3. 规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;而偶数号哲学家则相反。

​ 下面我们对每种方法给出哲学家进程的伪代码。

5.解决哲学家进餐问题—方法一

​ 对于方法一,至多只允许有四位哲学家同时去拿左边的筷子,我们可以简单的通过增加一个信号量实现,通过这个信号量限定哲学家并发去进餐的数量。

semaphore mutex[5] = {1,1,1,1,1};       //初始化信号量
semaphore count = 4;   //控制最多允许四位哲学家同时进餐void philosopher(int i){do {//thinking     //思考p(count);       //判断是否超过四人准备进餐P(mutex[i]);  //判断缓冲池中是否仍有空闲的缓冲区P(mutex[(i+1)%5]);//判断是否可以进入临界区(操作缓冲池)//...//eat           //进餐//...V(mutex[i]);//退出临界区,允许别的进程操作缓冲池V(mutex[(i+1)%5]);//缓冲池中非空的缓冲区数量加1,可以唤醒等待的消费者进程V(count);//用餐完毕,别的哲学家可以开始进餐}while(true);
}

6.解决哲学家进餐问题—方法二

​ 第二种方法,也就是使用AND型信号量,同时对哲学家左右两边的筷子同时申请。下面是伪代码:

semaphore mutex[5] = {1,1,1,1,1};       //初始化信号量void philosopher(int i){do {//thinking      //思考Swait(mutex[i], mutex[(i+1)%5]);//判断哲学家左边和右边的筷子是否同时可用//...//eat        //...Ssignal(mutex[i], mutex[(i+1)%5]);//进餐完毕,释放哲学家占有的筷子}while(true);
}

​ 对应的AND型信号量的实现可以参看我的另一篇博文。

7.解决哲学家进餐问题—方法三

​ 对于第三种,需要在代码中添加个判断,来决定获取左、右筷子的顺序,其伪代码如下:

semaphore mutex[5] = {1,1,1,1,1};       //初始化信号量void philosopher(int i){do {//thinking  if(i%2 == 1){P(mutex[i]);//判断哲学家左边的筷子是否可用P(mutex[(i+1)%5]);//判断哲学家右边的筷子是否可用}else{P(mutex[(i+1)%5]);//判断哲学家右边的筷子是否可用P(mutex[i]);//判断哲学家左边的筷子是否可用}//...//eat//...V(mutex[i]);//退出临界区,允许别的进程操作缓冲池V(mutex[(i+1)%5]);//缓冲池中非空的缓冲区数量加1,可以唤醒等待的消费者进程}while(true);
}

8.测试

​ 这里我们通过Java模拟实现哲学家进餐问题,这里我们使用方法一(其他几种方式只需修改对应哲学家线程中的代码即可),下面是具体的代码:

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;/*** 者削减进餐问题*/
@Slf4j
public class PhilosophersTest {static final Semaphore count = new Semaphore(4);static final Semaphore[] mutex = {new Semaphore(1), new Semaphore(1),new Semaphore(1), new Semaphore(1), new Semaphore(1)};static class Philosopher extends Thread {Philosopher(String name) {super.setName(name);}@Overridepublic void run() {do {try {count.acquire();Integer i = Integer.parseInt(super.getName());mutex[i].acquire();mutex[(i + 1) % 5].acquire();log.info("哲学家【{}】号吃了通心粉!", i);mutex[i].release();mutex[(i + 1) % 5].release();count.release();Thread.sleep(5000);} catch (InterruptedException e) {log.error("哲学家执行时产生异常!");}} while (true);}}public static void main(String[] args) {Philosopher p0 = new Philosopher("0");Philosopher p1 = new Philosopher("1");Philosopher p2 = new Philosopher("2");Philosopher p3 = new Philosopher("3");Philosopher p4 = new Philosopher("4");p0.start();p1.start();p2.start();p3.start();p4.start();}
}

​ 下图是代码的执行结果,这里的哲学家顺序进餐是因为哲学家每次进餐完毕后sleep了5S,如果想查看并发执行的情况,只需将sleep注释即可。


​ 又到了分隔线以下,本文到此就结束了,本文内容全部都是由博主自己进行整理并结合自身的理解进行总结,如果有什么错误,还请批评指正。

​ 本文的java代码都已通过测试,对其中有什么疑惑的,可以评论区留言,欢迎你的留言与讨论;另外原创不易,如果本文对你有所帮助,还请留下个赞,以表支持。

​ 如有兴趣,还可以查看我的其他几篇博客,都是OS的干货(目录),喜欢的话还请点赞、评论加关注_

参考文章列表:

1.进程同步机制-----为进程并发执行保驾护航

2.Java并发编程(JUC)模拟AND型信号量

3.Java并发编程(JUC)模拟信号量集

4.Java并发编程模拟管程(霍尔Hoare管程、汉森Hansan管程、MESA管程)

5.操作系统武功修炼心法

6.经典进程同步问题----生产者-消费者问题详解

6.经典进程同步问题----读者-写者问题详解

经典的进程同步问题-----哲学家进餐问题详解相关推荐

  1. 经典同步问题二——哲学家进餐问题

    系列同步问题: 经典同步问题一--生产者和消费者问题 https://blog.csdn.net/weixin_36465540/article/details/105560002 经典同步问题二-- ...

  2. 4个mos管驱动的全桥电路原理_最经典MOS管电路工作原理及详解没有之一

    欢迎加入技术交流QQ群(2000人):电力电子技术与新能源 1105621549 高可靠新能源行业顶尖自媒体 在这里有电力电子.新能源干货.行业发展趋势分析.最新产品介绍.众多技术达人与您分享经验,欢 ...

  3. 0832工作原理详解_最经典MOS管电路工作原理及详解没有之一

    欢迎加入技术交流QQ群(2000人):电力电子技术与新能源 1105621549 高可靠新能源行业顶尖自媒体 在这里有电力电子.新能源干货.行业发展趋势分析.最新产品介绍.众多技术达人与您分享经验,欢 ...

  4. 调包侠福音!机器学习经典算法开源教程(附参数详解及代码实现)

    Datawhale 作者:赵楠.杨开漠.谢文昕.张雨 寄语:本文针对5大机器学习经典算法,梳理了其模型.策略和求解等方面的内容,同时给出了其对应sklearn的参数详解和代码实现,帮助学习者入门和巩固 ...

  5. 八道超经典指针面试题(三千字详解)

    目录 第一题: 第二题: 第三题: 第四题: 第五题: 第六题: 第七题: 第八题: 第一题: int main() {int a[5] = { 1, 2, 3, 4, 5 };int *ptr = ...

  6. 递归经典例题 --- 汉诺塔(图文详解)

    目录 一.介绍 二.游戏规则 三.玩法简介 四.算法分析 五.代码解析 六.源码 七.递归过程详解 一.介绍 汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具.大梵 ...

  7. (王道408考研操作系统)第二章进程管理-第三节10:经典同步问题之哲学家进餐问题

    本文接: (王道408考研操作系统)第二章进程管理-第三节6:经典同步问题之生产者与消费者问题 ((王道408考研操作系统)第二章进程管理-第三节7:经典同步问题之多生产者与多消费者问题 (王道408 ...

  8. 经典Seq2Seq与注意力Seq2Seq模型结构详解

    介绍 在本文中,我们将分析一个经典的序列对序列(Seq2Seq)模型的结构,并演示使用注意解码器的优点. 这两个概念将为理解本文提出的Transformer奠定基础,因为"注意就是您所需要的 ...

  9. 食物链(经典种类并查集问题)---详解

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形. A吃B, B吃C,C吃A. 现有N个动物,以1-N编号. 每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用 ...

  10. C语言经典贪心算法之加油站问题(详解)

    文章目录 一.贪心算法 二.加油站问题 一.贪心算法 贪心算法暗示一种不追求最优解,只希望找到较为满意解的方法.贪心算法省去了为找最优解要穷尽所有可能而必须耗费大量时间,因此它一般可以快速得到较为满意 ...

最新文章

  1. 部署 DevStack - 每天5分钟玩转 OpenStack(17)
  2. nodejs mysql备份_node.js实现备份mysql数据库功能
  3. 分布式系统原理 之2 基本副本协议
  4. js模块化之模块依赖处理
  5. linux与windows编码转化
  6. 带你学 Redis:Redis简介(一)
  7. 也许现在的前端,应该了解更多的算法
  8. 利用Fiddler下载旧版本 iOS App
  9. python编程输入名字配对情侣网名_输入名字制作情侣qq网名
  10. Python-OpenCV——Image Blurring(Image Smoothing)
  11. y7000电池固件_y7000怎么刷电池固件|Surface Pro 3固件更新:电池续航问题终解决
  12. 如何利用C#/C++调取创蓝253短信验证码
  13. 基于angularjs的单页面实例_angularjs网站开发实例
  14. php文件上传思想,php之文件上传
  15. 《对比Excel,轻松学习Python数据分析》读书笔记------数据运算
  16. 通过2-3-4树理解红黑树
  17. 【转载】《仙剑OL》主题曲_玩家版
  18. 杨辉三角 C语言实现【一维数组】
  19. Linuxer-Linux开发者自己的媒体第6月稿件和赠书名单
  20. 强化学习——Q-Learning算法原理

热门文章

  1. 脉冲神经网络 神经元模型-HH模型(1)
  2. 基于Tablet pc 的墨迹手写识别输入法
  3. NSIS 简易教程(四)
  4. 夜神模拟器+Xposed框架+JustTrustMe(用来禁用、绕过 SSL 证书检查)来突破SSL Pinning
  5. linux上的手机管家,腾讯手机管家官网版
  6. 如何把word文件转换成PDF格式?
  7. opencv图片保存0字节_Opencv中IplImage存储方式介绍
  8. 524MB的微信输入法:没广告 你会用吗
  9. Vue 单文件模板中覆盖引入库 CSS 样式
  10. WinNT无盘Win95维护经验