哲学家就餐问题。这是由计算机科学家Dijkstra提出的经典死锁场景。
原版的故事里有五个哲学家(不过我们写的程序可以有N个哲学家),这些哲学家们只做两件事--思考和吃饭,他们思考的时候不需要任何共享资源,但是吃饭的时候就必须使用餐具,而餐桌上的餐具是有限的,原版的故事里,餐具是叉子,吃饭的时候要用两把叉子把面条从碗里捞出来。很显然把叉子换成筷子会更合理,所以:一个哲学家需要两根筷子才能吃饭。
现在引入问题的关键:这些哲学家很穷,只买得起五根筷子。他们坐成一圈,两个人的中间放一根筷子。哲学家吃饭的时候必须同时得到左手边和右手边的筷子。如果他身边的任何一位正在使用筷子,那他只有等着。
原版的故事里有五个哲学家(不过我们写的程序可以有N个哲学家),这些哲学家们只做两件事--思考和吃饭,他们思考的时候不需要任何共享资源,但是吃饭的时候就必须使用餐具,而餐桌上的餐具是有限的,原版的故事里,餐具是叉子,吃饭的时候要用两把叉子把面条从碗里捞出来。很显然把叉子换成筷子会更合理,所以:一个哲学家需要两根筷子才能吃饭。
现在引入问题的关键:这些哲学家很穷,只买得起五根筷子。他们坐成一圈,两个人的中间放一根筷子。哲学家吃饭的时候必须同时得到左手边和右手边的筷子。如果他身边的任何一位正在使用筷子,那他只有等着。
假设哲学家的编号是A、B、C、D、E,筷子编号是1、2、3、4、5,哲学家和筷子围成一圈如下图所示:
/*
*哲学家就餐问题
*
* */
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#define N 5
int forks[5]={0,0,0,0,0};
pthread_mutex_t mutex[N];
void think()
{
printf("Philosopher is thinking...\n");
usleep(rand()%10);
}
void take_fork(int i)
{
pthread_mutex_lock(mutex+i);
//pthread_mutex_trylock(mutex+i);
//如果一个线程既想获得锁,又不想挂起等待,可以调用pthread_mutex_trylock,如果Mutex已经被另一个线程获得,这个函数会失败返回EBUSY,而不会使线程挂起等待。
}
void put_fork(int i){
pthread_mutex_unlock(mutex+i);
}
void eat(int i)
{
printf("The %dth philosopher is having dinner!\n",i);
}
void *philosopher(void *p)
{
while(1){
int i=(int)p;
think();
take_fork(i);
take_fork((i+1)%N);
eat(i);
put_fork(i);
put_fork((i+1)%N);
}
}
int main()
{
int i;
for(i=0;i<N;++i)
{
pthread_mutex_init(mutex+i,NULL);
}
pthread_t pid[N];//five philosopher
for(i=0;i<N;i++)
{
if(0!=pthread_create(pid+i,NULL,philosopher,(void*)i))
{
fprintf(stderr,"create pthread error!\n");
exit(2);
}
}
for(i=0;i<N;i++)
{
pthread_join(pid[i],NULL);
}
return 0;
}