/*
* 问题描述:哲学家就餐
* C/C++ 语言
*
* @author Erice_s
* binbin_Erices@163.com
* @date 2017/10/21
*
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX 5 // 五个哲学家
#define LEFT (i+MAX-1)%MAX //队列处理 左边的哲学家
#define RIGHT (i+1)%MAX // 右边的哲学家
enum {THINKING,HUNGRY,EATING} state[MAX];
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER,s[MAX]; //每个哲学家一个互斥量
void test(int i)
{
if(state[i]==HUNGRY && state[LEFT]!=EATING && state[RIGHT]!=EATING)
{
printf("the %d of phlosopher is eating...\n",i);
state[i] = EATING;
sleep(rand()%5);
}
}
void take_fork(int i) // 第 i 号哲学家拿叉子
{
pthread_mutex_lock(&mutex); //可以拿筷子,进行下一步,否则阻塞
pthread_mutex_lock(&s[i]); //第i个哲学家可以操作资源
state[i]=HUNGRY;
test(i);
pthread_mutex_unlock(&s[i]);
pthread_mutex_unlock(&mutex);
}
void put_fork(int i) // 第 i 号哲学家放叉子
{
pthread_mutex_lock(&mutex);
state[i]=THINKING; // 调整状态
test(LEFT); // 给左右吃的信号
test(RIGHT);
pthread_mutex_unlock(&mutex);
}
void thinking(int i)
{
printf("the %d of phlosopher is thinking...\n",i);
sleep(rand()%5);
}
void *dothing(void *p) // 五个哲学家开始拿叉子
{
int i=*(int *)p;
for(;;){ //哲学家生活方式交替的进行思考和进餐
thinking(i);
take_fork(i);
put_fork(i);
}
}
int main(void)
{
int i;
pthread_t tid[MAX];
for(i=0;i<MAX;i++)
pthread_create(&tid[i],NULL,dothing,(void*)&i);
for(i=0;i<MAX;i++)
pthread_join(tid[i],NULL);
return 0;
}
代码思想分析 :
上面的代码中,当哲学家饥饿的时候他会去拿他周围两边的叉子,当执行成功后便可以就餐。之后他放下叉子,通知周围两个人他放下了叉子。上面的代码可以保证不会有两个相邻的哲学家同时进餐。
避免死锁的解法 :
(1)至多允许有四个哲学家同时拿左边的叉子,最终能保证至少有一位哲学家能够进餐,并在其用毕时能释放两只叉子,从而使更多的哲学家能够吃饭。
(2)仅当哲学家的左右两只叉子都可以用时才允许他去吃饭。
(3)规定奇数号哲学家先拿起左边的叉子,然后再去拿右边的叉子;而偶数号哲学家相反。按照此规定,1,2号哲学家竞争1 号叉子;3,4号哲学家竞争3号叉子。五位哲学家都先竞争奇数号叉子,获得后,再去竞争偶数号叉子,最后总会有一个哲学家能获得两只叉子而吃饭。