问题描述:有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一支筷子,这样每个哲学家左右各有一支筷子。哲学家有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;//释放锁
}