哲学家就餐问题。这是由计算机科学家Dijksta提出的经典死锁场景
问题描述:有5个哲学家,这些哲学家只做两件事--思考和吃饭,他们思考的时候不需要任何共享资源,但是吃饭的时候必须使用餐具,而餐具是有限的。原版的故事里,餐具是叉子,吃饭的时候要用两把叉子把面条从碗里捞出来。很显然把叉子换成筷子更合理,所以:一个哲学家需要两根筷子才能吃饭。
现在引入问题:这些哲学家很穷,只买的起5根筷子。他们做成一圈,两个人的中间放一根筷子。哲学家吃饭的时候必须同时得到左边手和右边手的筷子。如果他们身边的任何一位正在使用筷子,那他只有等着。
假设哲学家的编号为A,B,C,D,E,筷子为1,2,3,4,5,哲学家和筷子围成一圈
序号 (哲学家) 左边 右边
A 5 1
B 1 2
C 2 3
D 3 4
E 4 5
每个哲学家均为一个单独的线程,每个线程循环左以下动作:思考rand()% 10秒,然后先拿左手边的筷子再拿右边的筷子(筷子这种资源可以用mutex表示),有任何一边拿不到就一直等着,全拿到就吃饭rand()%10秒,然后放下筷子。
编写程序仿真哲学家就餐的场景:
philosopher A fetches chopsticks 5
philosopher B fetches chopsticks 1
...................
要想不产生死锁,只能用trylock,而不能用lock,否则有可能产生阻塞
代码(有点儿繁琐):
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t one_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t two_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t three_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t four_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t five_mutex = PTHREAD_MUTEX_INITIALIZER;
void think(void)
{
usleep(rand() % 10);
}
void eat(void)
{
usleep(rand() % 10);
}
void *thr_fn1(void *arg)
{
while(1)
{
think();//先思考一会儿
printf("philosopher A is thinking\n");
if(pthread_mutex_trylock(&five_mutex) == 0)//成功获得锁5
{
printf("Philosopher A fetches chopstick 5\n");
if(pthread_mutex_trylock(&one_mutex) != 0)//如果没有获得锁1
{
pthread_mutex_unlock(&five_mutex);//解锁5
printf("Philosopher A releases chopstick 5\n");
continue;//接着尝试
}
//成功获得锁1
printf("Philosopher A fetches chopstick 1\n");
eat();//成功的话就eat
printf("philosopher A is eating\n");
pthread_mutex_unlock(&five_mutex);
pthread_mutex_unlock(&one_mutex);
printf("Philosopher A releases chopstick 5 -- 1\n");
}
think();//不成功的话就think
}
}
void *thr_fn2(void *arg)
{
while(1)
{
think();//不成功的话就sleep
printf("philosopher B is thinking\n");
if(pthread_mutex_trylock(&one_mutex) == 0)//成功获得锁x
{
printf("Philosopher B fetches chopstick 1\n");
if(pthread_mutex_trylock(&two_mutex) != 0)//如果没有获得锁y
{
pthread_mutex_unlock(&one_mutex);//解锁x
printf("Philosopher B releases chopstick 1\n");
continue;//接着尝试
}
//成功获得锁y
printf("Philosopher B fetches chopstick 2\n");
eat();
printf("philosopher B is eating\n");
pthread_mutex_unlock(&one_mutex);
pthread_mutex_unlock(&two_mutex);
printf("Philosopher B releases chopstick 1 -- 2\n");
}
think();//不成功的话就sleep
}
}
void *thr_fn3(void *arg)
{
while(1)
{
think();//不成功的话就sleep
printf("philosopher C is thinking\n");
if(pthread_mutex_trylock(&two_mutex) == 0)//成功获得锁x
{
printf("Philosopher C fetches chopstick 2\n");
if(pthread_mutex_trylock(&three_mutex) != 0)//如果没有获得锁y
{
pthread_mutex_unlock(&two_mutex);//解锁x
printf("Philosopher C releases chopstick 2\n");
continue;//接着尝试
}
//成功获得锁y
printf("Philosopher C fetches chopstick 3\n");
eat();
printf("philosopher C is eating\n");
pthread_mutex_unlock(&two_mutex);
pthread_mutex_unlock(&three_mutex);
printf("Philosopher C releases chopstick 2 -- 3\n");
}
think();//不成功的话就sleep
}
}
void *thr_fn4(void *arg)
{
while(1)
{
think();//不成功的话就sleep
printf("philosopher D is thinking\n");
if(pthread_mutex_trylock(&three_mutex) == 0)//成功获得锁x
{
printf("Philosopher D fetches chopstick 3\n");
if(pthread_mutex_trylock(&four_mutex) != 0)//如果没有获得锁y
{
pthread_mutex_unlock(&three_mutex);//解锁x
printf("Philosopher D releases chopstick 3\n");
continue;//接着尝试
}
//成功获得锁y
printf("Philosopher D fetches chopstick 4\n");
eat();
printf("philosopher D is eating\n");
pthread_mutex_unlock(&three_mutex);
pthread_mutex_unlock(&four_mutex);
printf("Philosopher D releases chopstick 3 -- 4\n");
}
think();//不成功的话就sleep
}
}
void *thr_fn5(void *arg)
{
while(1)
{
think();//不成功的话就sleep
printf("philosopher E is thinking\n");
if(pthread_mutex_trylock(&four_mutex) == 0)//成功获得锁x
{
printf("Philosopher E fetches chopstick 4\n");
if(pthread_mutex_trylock(&five_mutex) != 0)//如果没有获得锁y
{
pthread_mutex_unlock(&four_mutex);//解锁x
printf("Philosopher E releases chopstick 4\n");
continue;//接着尝试
}
//成功获得锁y
printf("Philosopher E fetches chopstick 5\n");
eat();
printf("philosopher E is eating\n");
pthread_mutex_unlock(&four_mutex);
pthread_mutex_unlock(&five_mutex);
printf("Philosopher E releases chopstick 4 -- 5\n");
}
think();//不成功的话就sleep
}
}
int main(void)
{
pthread_t tid1,tid2,tid3,tid4,tid5;
srand((unsigned int)time(NULL));
pthread_create(&tid1,NULL,thr_fn1,NULL);
pthread_create(&tid2,NULL,thr_fn2,NULL);
pthread_create(&tid3,NULL,thr_fn3,NULL);
pthread_create(&tid4,NULL,thr_fn4,NULL);
pthread_create(&tid5,NULL,thr_fn5,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
pthread_join(tid4,NULL);
pthread_join(tid5,NULL);
return 0;
}