哲学家算法
操作系统中,为了避免互斥资源使用导致死锁
问题,有很多的解决方法,其中一种方法就是哲学家算法。
首先说一下什么是哲学家算法,有5个哲学家,他们只会思考和吃饭,但是在一个圆形的桌子上面
只有5支筷子,这些哲学家什么时候来吃东西是不确定的,也就是说,同一时间可能会有5个人来进食,也可能一个人也没有。
要想吃饭,必须有两双筷子,所以要约定一种取得筷子的方法。如果没有什么约束条件,可能出现下面的状况:
1、
假设哲学家吃饭的时候会首先取得自己左侧的筷子,可能在某一瞬间
5个人同时吃饭并
同时拿起了左面的筷子,得不到另一支筷子时就放下了筷子并同时拿起了自己右侧的筷子,如此反复循环。。。导致程序无法向前运行。
2、假设哲学家吃饭的时候首先拿取左侧的筷子,再检查右侧的筷子
,如果右侧的筷子不用,则放下自己已经取得的筷子,过一段时间后在重复这一个过程。这个方法看似可行,仔细一想却和1中的情况差不多,可能在某一个瞬间,5个人同时启用这个方法,又会出现1中的情况。。。程序还是不会运行。
为了避免出现这种情况,有了哲学家算法,其中一种方案是:
1、3、5(奇数)号哲学家会分别先取离自己最近的奇数号筷子,然后再取离自己最近的右侧的筷
子,2、4(偶数)号则分别取右侧最近的奇数号筷子,再去竞争离自己最近
的偶数号筷子
。哲学家会先竞争奇数位上的筷子,再去竞争偶数位上的筷子,总有一个能吃上饭,且根据FIFO队列,其他等待的哲学家会依次得到筷子吃饭故,可以实现程序的正常运行。具体代码如下:
package Philosopher;
public class Semaphore {
int count;//共享的资源数的数量。
public Semaphore (int count){
this.count=count;
}
//操作系统p操作
public synchronized void P(){
count--;
if(count<0){//如果资源小于0,则加入等待队列中,为阻塞状态。
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//操作系统v操作
public synchronized void V(){
count++;
if(count<=0){//如果不大于0,则唤醒等待的线程。
notify();
}
}
}
上面出现的P操作和V操作是一组运行过程中不可停止的原始操作,属于计算机原语。具体知识见操作系统原理。
public class Philosopher extends Thread{
private int n;
public Philosopher(int n){
this.n=n;
}
//重写run方法
public void run(){
/**
* 拿筷子的时候,约定:
* Philosopher编号为奇数的先取自己右边的筷子,编号为偶数的先取自己左边的筷子。
*/
while(true){
if(n%2==0){
System.out.println("Philosopher"+n+"尝试取得"+(n+1)%5+"支筷子 ");
Starteat .chopsticks[(n+1)%5].P();
System.out.println("Philosopher"+n+"已经取得"+(n+1)%5+"支筷子");
System.out.println("Philosopher"+n+"尝试取得"+(n)%5+"支筷子");
Starteat .chopsticks[(n)%5].P();
System.out.println("Philosopher"+n+"已经取得"+(n)%5+"支筷子");
System.out.println("Philosopher"+n+"正在吃饭中。。。。。。");
try {
Thread.sleep(1);//吃饭时间。。
} catch (InterruptedException e) {
e.printStackTrace();
}
Starteat .chopsticks[(n+1)%5].V();
Starteat .chopsticks[(n)%5].V();
System.out.println("Philosopher"+n+"放下了第"+n+"和"+n+1);
System.out.println("Philosopher"+n+"已经进食完毕。开始思考。。。。");
}
else {
System.out.println("Philosopher"+n+"尝试取得"+(n)%5+"支筷子");
Starteat .chopsticks[(n)%5].P();
System.out.println("Philosopher"+n+"已经取得"+(n)%5+"支筷子");
System.out.println("Philosopher"+n+"尝试取得"+(n+1)%5+"支筷子");
Starteat .chopsticks[(n+1)%5].P();
System.out.println("Philosopher"+n+"已经取得"+(n+1)%5+"支筷子");
System.out.println("Philosopher"+n+"正在吃饭中。。。。。。");
try {
Thread.sleep(1);//吃饭时间。。
} catch (InterruptedException e) {
e.printStackTrace();
}
Starteat .chopsticks[(n+1)%5].V();
Starteat .chopsticks[(n)%5].V();
System.out.println("Philosopher"+n+"放下了第"+n+"和"+n+1);
System.out.println("Philosopher"+n+"已经进食完毕。开始思考。。。。");
}
}
}
}
由于两个人之间是竞争一支筷子,所以semaphore设置为1.
package Philosopher;
public class Starteat {
static Semaphore [] chopsticks = new Semaphore [5];
public static void main(String [] agrs){
for(int i=0;i<5;i++){
chopsticks[i] = new Semaphore(1);
}
for(int i=0;i<5;i++){
new Philosopher(i).start();
}
}
}
代码实现起来比较容易,这种方法只是哲学家算法中的一种,你也可以限制同时吃饭的人数(如最多只能允许4人同时吃饭
)来解决哲学家吃饭饿死的问题。只是效率会不同。本人水平有限,不足之处请大家多多包涵。
分享到:
相关推荐
哲学家算法是操作系统设计中的一个经典问题,它模拟了五个哲学家围坐在一张圆桌边,每个人面前都有一根筷子。哲学家们交替地思考和吃饭,但若五个人同时拿起左右两边的筷子,就会陷入无法进食的死锁状态。为了解决这...
在这个C#实现的哲学家算法演示中,我们可以通过以下关键知识点来理解: 1. **并发控制**:哲学家就餐问题展示了在多线程环境中可能出现的并发问题,如死锁。在操作系统中,通过锁、信号量、条件变量等机制来协调...
操作系统实验——哲学家算法c++ 参考一下吧
操作系统课程设计中的“哲学家算法”是一个经典的多线程同步问题,源于计算机科学家 Edsger Dijkstra 提出的示例。这个例子描述了五个哲学家围坐在一张圆桌旁,每人一边有一根筷子。他们思考时需要两根筷子来吃饭。...
哲学家算法,也被称为Dining Philosophers Problem,是计算机科学中的一个经典问题,它由艾兹格·迪科斯彻在1965年提出,用于揭示并发控制和死锁现象。在这个问题中,五位哲学家围坐在一张桌子旁,每人面前都有一根...
《哲学家问题算法代码解析》 ...然而,为了彻底解决哲学家问题,我们需要更高级的并发控制策略,如银行家算法或使用Java的`ReentrantLock`等工具。这为深入理解并发编程和死锁预防提供了宝贵的实践案例。
在C++Builder中实现哲学家进餐算法,主要涉及到线程同步和互斥量(mutex)的概念。C++Builder提供了如`TThread`类和`CriticalSection`等工具来处理线程同步。以下是该问题的关键知识点: 1. **线程**: 在多线程环境...
8. **并发控制策略**:解决哲学家问题有多种策略,如避免死锁的银行家算法、优先级逆置法等。在Qt实现中,我们可以选择最简单的“先取左边筷子再取右边”规则,这样可以保证不会出现环形等待,避免死锁。 通过以上...
在操作系统的世界里,"哲学家进餐问题"是一个经典的多线程或进程同步问题,它由计算机科学家Edsger Dijkstra提出,用以演示资源竞争可能导致的死锁现象。在这个问题中,五个哲学家围坐在一张圆桌旁,每个人面前都有...
7. **哲学家算法**: - 每个哲学家的动作包括思考、饥饿、取筷子、进食和放筷子。 - 五个哲学家的并发动作需要通过多线程和信号量协调,以确保不会出现死锁和饿死。 8. **并发控制**: - 在实现中,需要测试哲学...
哲学家就餐问题的分析与代码,供大家参考吧,很详细
实验一 进程同步互斥——不死锁的哲学家问题 (1)输入的形式和输入值的范围; 由于这个是一个按钮实现监控,界面提供视图的程序,所以并不需要别的附加的输入,只需要点击相应的按钮即可。按钮有开始、暂停、结束...
经典算法解决哲学家进餐问题通常有两种策略:避免死锁和预防死锁。 1. **避免死锁**: 这种策略是在每次哲学家试图拿起筷子时检查是否会导致死锁。例如,可以使用一个循环等待图来表示当前状态,如果不存在形成...
解决方法包括使用信号量、银行家算法等,确保资源分配策略能防止死锁,并保证所有哲学家都能公平地获得食物。 3. **生产者-消费者问题**: 在这个经典的并发问题中,生产者生成产品并放入缓冲区,而消费者从缓冲区...
哲学家就餐算法是计算机科学中一个经典的问题,它源自图灵奖得主Edsger Dijkstra提出的一个模拟并发问题,旨在探讨多线程环境下的死锁预防策略。在这个问题中,有五个哲学家围坐在一张圆桌旁,每个人面前都有一根...
### 哲学家就餐问题详解 #### 一、问题背景及定义 哲学家就餐问题是并发控制领域中的一个经典问题,通常被用来说明进程同步中死锁的问题。该问题描述为:有五位哲学家围坐在一张圆桌旁,每个人面前有一只筷子(共...
《C#实现哲学家进餐算法详解》 在软件工程领域,模拟问题并寻找解决方案是常见的一种编程训练。"哲学家进餐问题"(Dining Philosophers Problem)就是这样一个经典的多线程同步问题,它源自计算机科学家Edsger ...