哲学家问题

问题描述:有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一支筷子,这样每个哲学家左右各有一支筷子。哲学家有2个状态,思考或者拿起筷子吃饭。如果哲学家拿到一只筷子,不能吃饭,直到拿到2只才能吃饭,并且一次只能拿起身边的一支筷子。一旦拿起便不会放下筷子直到把饭吃完,此时才把这双筷子放回原处。如果,很不幸地,每个哲学家拿起他或她左边的筷子,那么就没有人可以吃到饭了。
哲学家进餐问题是一个多线程运用的经典例子,涉及到线程同步/互斥,临界区访问问题以及死锁问题。

问题思考:哲学家依次编号为:1,2,3,4,5,每个哲学家左侧的筷子编号与哲学家的编号相同,则哲学家有侧的筷子编号为哲学家的编号+1并对5取余。假设每个哲学家总是先拿起左侧的筷子,那么,若5个哲学家线程都拿起了一根筷子,就将导致死锁的发生。

解决方案一:最多允许4位哲学家拿起他左侧的筷子,最终保证至少有一位哲学家可以吃到饭,并在用餐完毕后释放筷子,使其他哲学家也可以吃到饭。

`#include<stdio.h>
#include<time.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
int chops[5]={0};//5只筷子的状态
int phil[5]={1,2,3,4,5};//5位哲学家
void *philos(void *);
int main()
{
	srand(time(NULL));
	int i;
	pthread_t  pthnum[5];
	void *stat;
	for(i=0;i<5;i++)
		if(pthread_create(&pthnum[i],NULL,philos,(void *)&phil[i])==-1)
		{
			printf("creat error!\n");
			exit(1);
		}
	for(i=0;i<5;i++)
		if(pthread_join(pthnum[i],(void *)&stat)==-1)
		{
			printf("pthread-join  error!\n");
			exit(1);
		}
	return 0;
}
void *philos(void *arg)
{
	int m=*(int *)arg;
	int left=m,right=(m+1)%5;
	while(1)
	{
		printf("哲学家%d正在思考问题\n",m);
		sleep(rand()%5);
		printf("哲学家%d饿了\n",m);
		while(1)//判断是否有4位哲学家拿到了筷子
		{
			int sum=chops[0]+chops[1]+chops[2]+chops[3]+chops[4];
			if(sum<4)
				break;
		}
		while(chops[left]==1);
		chops[left]==1;
		printf("哲学家%d拿起了%d号筷子,现在只有一只筷子,不能进餐\n",m,left);
		while(chops[right]==1);
		chops[right]=1;
		printf("\033[0;45;47m哲学家%d拿起了%d号筷子,现在有两只筷子,开始进餐\033[0m\n",m,right);
		sleep(rand()%3);
		printf("\033[0;33;47m哲学家%d进餐完毕\033[0m\n",m);
		chops[left]=0;
		printf("哲学家%d放下了%d号筷子\n",m,left);
		chops[right]=0;
		printf("哲学家%d放下了%d号筷子\n",m,right);
	}
}`

解决方案二:当一位哲学家进餐完毕时,才允许其他哲学家拿起筷子

#include<stdio.h>
#include<time.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
int chops[5]={0},phil[5]={1,2,3,4,5},lock=0;
void *philos(void *);
int main()
{
	srand(time(NULL));
	int i;
	pthread_t  pthnum[5];
	void *stat;
	for(i=0;i<5;i++)
		if(pthread_create(&pthnum[i],NULL,philos,(void *)&phil[i])==-1)
		{
			printf("creat error!\n");
			exit(1);
		}
	for(i=0;i<5;i++)
		if(pthread_join(pthnum[i],(void *)&stat)==-1)
		{
			printf("pthread-join  error!\n");
			exit(1);
		}
	return 0;
}
void *philos(void *arg)
{
	int m=*(int *)arg;
	int left=m,right=(m+1)%5;
	while(1)
	{
		printf("哲学家%d正在思考问题\n",m);
		sleep(rand()%5);
		printf("哲学家%d饿了\n",m);
		while(lock==1);//上锁
		lock=1;
		while(chops[left]==1);
		chops[left]==1;
		printf("哲学家%d拿起了%d号筷子,现在只有一只筷子,不能进餐\n",m,left);
		while(chops[right]==1);
		chops[right]=1;
		printf("\033[0;45;47m哲学家%d拿起了%d号筷子,现在有两只筷子,开始进餐\033[0m\n",m,right);
		sleep(rand()%3);
		printf("\033[0;33;47m哲学家%d进餐完毕\033[0m\n",m);
		chops[left]=0;
		printf("哲学家%d放下了%d号筷子\n",m,left);
		chops[right]=0;
		printf("哲学家%d放下了%d号筷子\n",m,right);
		lock=0;//释放锁
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值