哲学家进餐问题(linux下C/C++源码)

哲学家进餐问题(linux下C/C++源码)
题目描述:
题目自行百度吧。
思路:
5个哲学家相当于5的线程,5支筷子相当于5把mutex锁。
假如他们都拿左手边的筷子,这时就容易发生死锁,即谁都就不了餐(震荡行为)。
此时就需要其中一位哲学家放弃手中的资源。为了避免这种行为,我们使前四位哲学家都拿起左手的筷子,而第五位哲学家拿右手的筷子,即与第四位哲学家争夺资源,如果争夺成功,此时去拿左手筷子即可,如果争夺失败,那么第一位哲学家必然能拿到第五位哲学家的左手筷子,必然发生不了死锁现象。
选用互斥锁mutex,如创建5个, pthread_mutex_t m[5];
模型抽象:
5个哲学家 --> 5个线程; 5支筷子 --> 5把互斥锁 int left(左手), right(右手)
5个哲学家使用相同的逻辑,可通用一个线程主函数,void *tfn(void *arg),使用参数来表示线程编号:int i = (int)arg;
哲学家线程根据编号知道自己是第几个哲学家,而后选定锁,锁住,吃饭。否则哲学家thinking。
A B C D E
5支筷子,在逻辑上形成环: 0 1 2 3 4 分别对应5个哲学家:

所以有:

if(i == 4)	
	left = i, right = 0;
else 
	left = i, right = i+1;

振荡:如果每个人都攥着自己左手的锁,尝试去拿右手锁,拿不到则将锁释放。过会儿五个人又同时再攥着左手锁尝试拿右手锁,依然拿不到。如此往复形成另外一种极端死锁的现象——振荡。

避免振荡现象:只需5个人中,任意一个人,拿锁的方向与其他人相逆即可(如:E,原来:左:4,右:0 现在:左:0, 右:4)。
所以以上if else语句应改为:

if(i == 4)	
	left = 0, right = i;
else 
	left = i, right = i+1;

而后, 首先应让哲学家尝试加左手锁:

while { 
	pthread_mutex_lock(&m[left]); 	
}
	如果加锁成功,函数返回再加右手锁,如果失败,应立即释放左手锁,等待。
	若,左右手都加锁成功 --> 吃 --> 吃完 --> 释放锁
	(应先释放右手、再释放左手,是加锁顺序的逆序)

主线程(main)中,初始化5把锁,销毁5把锁,创建5个线程(并将i传递给线程主函数),回收5个线程。
避免死锁的方法:
1. 当得不到所有所需资源时,放弃已经获得的资源,等待。
2. 保证资源的获取顺序,要求每个线程获取资源的顺序一致。如:A获取顺序1、2、3;B顺序应也是1、2、3。若B为3、2、1则易出现死锁现象。
在这里插入图片描述
代码如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

pthread_mutex_t m[5];

void* tfn(void *arg)
{
	int i = (int)arg;
	int left,right;
	if(i == 4){
		//防止震荡现象发生。
		left = 0;
		right = i;
	}
	else{
		left = i;
		right = i+1;
	}
	while (1) {
		pthread_mutex_lock(&m[left]);
		int ret = pthread_mutex_trylock(&m[right]); 	
		if(ret != 0){
			//尝试拿右手筷子失败,把左手的筷子释放
			pthread_mutex_unlock(&m[left]);
			printf("哲学家%d没有抢到筷子...\n",i);
			continue;
		}
		//拿到了两支筷子
		//吃面
		printf("哲学家%d正在吃面...\n",i);
		//吃完面,释放筷子.
		pthread_mutex_unlock(&m[left]);
		pthread_mutex_unlock(&m[right]);
		//sleep(1);
	}
}

int main()
{
	pthread_t pth[5];
	//初始化五把锁
	for(int i = 0;i < 5;i++){
		pthread_mutex_init(&m[i],NULL);
	}
	//创建5个线程,相当于5个哲学家
	for(int i = 0;i < 5;i++){
		pthread_create(&pth[i],NULL,tfn,(void*)i);
	}
	//回收子线程
	for(int i = 0;i < 5;i++){
		pthread_join(pth[i],NULL);
	}
	//退出
	pthread_exit(NULL);
	
}


  • 8
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,让我们来模拟五个哲学家哲学家进餐问题。 首先,让我们定义一下问题:五个哲学家坐在圆桌前,每个哲学家面前有一碗米饭和一只筷子,相邻的哲学家之间共用一只筷子。哲学家们交替思考和进餐,思考时不需要用到筷子,但进餐时必须同时拿起相邻两只筷子。如果某个哲学家正在使用左右两只筷子,则其他哲学家必须等待,直到该哲学家进餐完毕才能继续进餐。 下面是一个可能的解决方案,使用Python语言实现: ```python import threading class Philosopher(threading.Thread): def __init__(self, name, left_fork, right_fork): threading.Thread.__init__(self) self.name = name self.left_fork = left_fork self.right_fork = right_fork def run(self): while True: self.think() self.eat() def think(self): print("{} is thinking...".format(self.name)) def eat(self): print("{} is hungry and trying to pick up the forks...".format(self.name)) fork1, fork2 = self.left_fork, self.right_fork while True: fork1.acquire() locked = fork2.acquire(False) if locked: break fork1.release() print("{} swaps forks".format(self.name)) fork1, fork2 = fork2, fork1 else: return self.dine() fork2.release() fork1.release() def dine(self): print("{} starts eating...".format(self.name)) # 哲学家进餐时的代码 if __name__ == "__main__": forks = [threading.Lock() for i in range(5)] philosophers = [Philosopher("Philosopher {}".format(i), forks[i % 5], forks[(i + 1) % 5]) for i in range(5)] for philosopher in philosophers: philosopher.start() ``` 在这个实现中,我们定义了一个Philosopher类,它继承了Python的threading.Thread类。每个哲学家都是一个线程,由线程的run方法控制思考和进餐的过程。 在进餐的过程中,哲学家首先尝试拿起左边的筷子,然后再尝试拿起右边的筷子。如果左右两只筷子都被占用,则该哲学家会先释放左边的筷子,然后等待一段时间后再重试。如果成功拿起左右两只筷子,则可以开始进餐,直到进餐完毕后将两只筷子释放。 最后,我们创建了五个哲学家和五只筷子,并让每个哲学家开始思考和进餐。这样就模拟了五个哲学家哲学家进餐问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值