【操作系统作业】哲学家就餐问题

2023-12-12 23:10

本文主要是介绍【操作系统作业】哲学家就餐问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、题目
  • 二、题目解析
  • 三、代码实现
  • 四、运行效果截图
  • 结语


一、题目

教材提供一个哲学家就餐问题的解决方案的框架。本问题要求通过pthreads 互斥锁来实现这个解决方案。
哲学家 首先创建 5 个哲学家,每个用数字 0~4 来标识。每个哲学家作为一个单独的 线程运行。 可使用 Pthreads 创建线程。哲学家在思考和吃饭之间交替。为了模拟这两种活动,请让线程休眠 1 到 3 秒钟。当哲学家想要吃饭时,他调用函数:
pickup_forks(int philosopher _number) 其中,philosopher _number
为想吃饭哲学家的数字。当哲学家吃完后,他调用函数:

return _forks(int philosopher _number)

Pthreads 条件变量 Pthreads 条件变量使用数据类型 pthread_cond_t,采用函数 pthread cond
init()初始化。以下代码创建并初始化条件变量及其关联的互斥锁:

pthread _mutex_ t mutex;
pthread_ cond_ t cond _var;
pthread _mutex_ init(&mutex,NULL);
pthread _cond_ init(&cond _var,NULL);

函数 pthread_cond_wait()用于等待条件变量。下面的代码采用 Pthreads条件变量,说明线程如何等待条件 a==b 变为
true。

pthread _mutex_ lock(&mutex);
while (a != b)
pthread_cond _wait(&mutex, &cond var);
pthread _mutex_ unlock(&mutex);

与条件变量关联的互斥锁在调用pthread_cond_wait()函数之前,应加锁,因为保护条件语句中的数据,避免竞争条件。一旦获得锁,线程可以检查条件。如果条件不成立,然后线程调用 pthread_cond_wait(),传递互斥锁和条件变量作为参数。调用pthread_cond_wait()释放互斥锁,从而允许另一个线程访问共享变量,也可更新其值,以便条件语句的计算结果为真。(为了防止程序错误,重要的是将条件语句放在循环中,以便在被唤醒后重新检查条件。)修改共享数据的线程可以调用 pthread_cond_signal()函数,从而唤醒一个等待条件变量的线程。这个代码如下:

pthread_ mutex_ lock(&mutex);
a = b;
pthread_ cond_ signal(&cond var);
pthread _mutex_ unlock(&mutex);

需要注意的是,调用pthread_cond_signal()不会释放互斥锁。随后调用pthread_mutex_unlock()释放互斥锁。一旦互斥锁被释放,唤醒线程成为互斥锁的所有者,并将控制权返回到对pthread cond wait()的调用。

二、题目解析

题目是书上的哲学家就餐问题,要求用互斥锁解决。
这题的关键在于筷子这个资源的合理使用,书上给出了三种不同的解决思路:
在这里插入图片描述
其实三种方法的核心就是为了解决死锁问题。

什么是死锁呢?
用专业点的话说就是:一组互相竞争资源的线程因互相等待,导致“永久”阻塞的现象

说白了,就是你拿了我想要拿的资源,我拿了你想要拿的资源,而双方各执一词,导致一直无法解决问题

那我的思路就是:
双方各退一步,当发现我想要的资源不够我完成我所需的事情时,那就把之前拿到的资源放回。这样就不会导致双方互相等待导致死锁的情况。

当然思路不止一种,在极客时间的Java并发编程实战中有讲到死锁发生的条件:

只有以下这四个条件都发生时才会出现死锁:

  • 互斥,共享资源 X 和 Y 只能被一个线程占用;
  • 占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不释放共享资源 X;
  • 不可抢占,其他线程不能强行抢占线程 T1 占有的资源;
  • 循环等待,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占有的资源,就是循环等待。

如何解决死锁呢?打破任意一个条件即可。

其中,互斥这个条件我们没有办法破坏,因为我们用锁为的就是互斥。不过其他三个条件都是有办法破坏掉的,到底如何做呢?

  1. 对于“占用且等待”这个条件,我们可以一次性申请所有的资源,这样就不存在等待了。
  2. 对于“不可抢占”这个条件,占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源,这样不可抢占这个条件就破坏掉了。
  3. 对于“循环等待”这个条件,可以靠按序申请资源来预防。所谓按序申请,是指资源是有线性顺序的,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样线性化后自然就不存在循环了。

如果感兴趣的话可以去仔细看看05 | 一不小心就死锁了,怎么办?,这里就不多介绍了。

好了,回到正题上来,既然我们的思路就是拿不到资源就选择退让,我们可以借用Java里的ReentrantLock类中trylock()方法实现,该方法的作用就是尝试锁住该资源。和lock()方法不同的是,如果该资源已经上锁,那么线程不会阻塞,而是返回flase,表示无法上锁,当然还可以加入参数让它再尝试几秒,比如:

lock.tryLock(1, TimeUnit.SECONDS))

而具体用法就是

if (lock.tryLock(1, TimeUnit.SECONDS)) {try {...} finally {lock.unlock();}
}

三、代码实现

package com.dreamchaser.concurrent;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 哲学家就餐问题*/
public class Proj3_02 {static final Lock[] locks=new Lock[5];static {for (int i=0;i<locks.length;i++){locks[i]=new ReentrantLock();}}public static void main(String[] args) {Philosopher philosopher0=new Philosopher("张三",1000,0);Philosopher philosopher1=new Philosopher("李四",800,1);Philosopher philosopher2=new Philosopher("王五",400,2);Philosopher philosopher3=new Philosopher("jhl",2000,3);Philosopher philosopher4=new Philosopher("ghlcl",2000,4);philosopher0.start();philosopher1.start();philosopher2.start();philosopher3.start();philosopher4.start();//死循环,防止主线程退出导致进程关闭while (true){}}static class Philosopher extends Thread{private String name;private long time;private int num;public Philosopher(String name, long time, int num) {this.name = name;this.time = time;this.num = num;}@Overridepublic void run() {while (true){System.out.println(num+"号哲学家"+name+"正在思考...");//模拟思考的过程try {Thread.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(num+"号哲学家"+name+"饿了,想来吃饭...");if (locks[num].tryLock()){try {System.out.println(num+"号哲学家"+name+"拿到了左边的筷子!");if (locks[(num+1)%5].tryLock()){try {System.out.println(num+"号哲学家"+name+"拿到了右边的筷子!");System.out.println(num+"号哲学家"+name+"开始吃饭!");//模拟哲学家吃饭的过程Thread.sleep(time);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(num+"号哲学家"+name+"放下了右边的筷子!");locks[(num+1)%5].unlock();}}else {System.out.println(num+"号哲学家"+name+"没拿到了右边的筷子!被迫思考...");}}finally {System.out.println(num+"号哲学家"+name+"放下了左边的筷子!");locks[num].unlock();}}else {System.out.println(num+"号哲学家"+name+"没拿到了左边的筷子!被迫思考...");}System.out.println(num+"号哲学家"+name+"思考ing...");//模拟思考过程try {Thread.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}}}}
}

四、运行效果截图

在这里插入图片描述

在这里插入图片描述

结语

以上是我的实现思路。希望我的思路能个各位有所帮助,当然,如果有什么意见或者建议的,欢迎在评论区评论。


最后,
愿我们以梦为马,不负青春韶华!
与君共勉!

这篇关于【操作系统作业】哲学家就餐问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/486270

相关文章

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

oracle数据库索引失效的问题及解决

《oracle数据库索引失效的问题及解决》本文总结了在Oracle数据库中索引失效的一些常见场景,包括使用isnull、isnotnull、!=、、、函数处理、like前置%查询以及范围索引和等值索引... 目录oracle数据库索引失效问题场景环境索引失效情况及验证结论一结论二结论三结论四结论五总结ora

element-ui下拉输入框+resetFields无法回显的问题解决

《element-ui下拉输入框+resetFields无法回显的问题解决》本文主要介绍了在使用ElementUI的下拉输入框时,点击重置按钮后输入框无法回显数据的问题,具有一定的参考价值,感兴趣的... 目录描述原因问题重现解决方案方法一方法二总结描述第一次进入页面,不做任何操作,点击重置按钮,再进行下

解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

《解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题》本文主要讲述了在使用MyBatis和MyBatis-Plus时遇到的绑定异常... 目录myBATis-plus-boot-starpythonter与mybatis-spring-b

mysql主从及遇到的问题解决

《mysql主从及遇到的问题解决》本文详细介绍了如何使用Docker配置MySQL主从复制,首先创建了两个文件夹并分别配置了`my.cnf`文件,通过执行脚本启动容器并配置好主从关系,文中还提到了一些... 目录mysql主从及遇到问题解决遇到的问题说明总结mysql主从及遇到问题解决1.基于mysql

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

如何安装HWE内核? Ubuntu安装hwe内核解决硬件太新的问题

《如何安装HWE内核?Ubuntu安装hwe内核解决硬件太新的问题》今天的主角就是hwe内核(hardwareenablementkernel),一般安装的Ubuntu都是初始内核,不能很好地支... 对于追求系统稳定性,又想充分利用最新硬件特性的 Ubuntu 用户来说,HWEXBQgUbdlna(Har

MAVEN3.9.x中301问题及解决方法

《MAVEN3.9.x中301问题及解决方法》本文主要介绍了使用MAVEN3.9.x中301问题及解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录01、背景02、现象03、分析原因04、解决方案及验证05、结语本文主要是针对“构建加速”需求交

Nginx、Tomcat等项目部署问题以及解决流程

《Nginx、Tomcat等项目部署问题以及解决流程》本文总结了项目部署中常见的four类问题及其解决方法:Nginx未按预期显示结果、端口未开启、日志分析的重要性以及开发环境与生产环境运行结果不一致... 目录前言1. Nginx部署后未按预期显示结果1.1 查看Nginx的启动情况1.2 解决启动失败的

CentOS系统使用yum命令报错问题及解决

《CentOS系统使用yum命令报错问题及解决》文章主要讲述了在CentOS系统中使用yum命令时遇到的错误,并提供了个人解决方法,希望对大家有所帮助,并鼓励大家支持脚本之家... 目录Centos系统使用yum命令报错找到文件替换源文件为总结CentOS系统使用yum命令报错http://www.cppc