问题描述:有五位哲学家围绕着餐桌坐,每一位哲学家要么思考,要么吃饭。为了吃饭,哲学家必须拿起两双筷子(分别放于左右两端)不幸的是,筷子的数量和哲学家相等,所以每只筷子必须由两位哲学家共享。
该问题是一个典型的互斥问题,有的操作系统教科书上说哲学家还可以有第三中状态,即等待状态。我个人觉得哲学家不应该有等待状态,即一个哲学家拿着一根筷子,等待旁边的哲学家放下另一根筷子。 虽然哲学家一次只能拿一根筷子,也就是说哲学家拿两根筷子的动作是分开的,但是就问题的解题思路来说,我们必须让哲学家拿两根筷子的连续动作是一个互斥的单元,即要么同时拿到两根筷子,要么放弃继续思考,等待机会再拿。而不应该让他只拿着一根筷子等待另一根。 试想,如果允许哲学家拿着一根筷子在那里等待,那么在理论上就必定会出现所有的哲学家都拿着一根筷子等待另一根筷子的局面,这就成了死锁。
给予以上分析,我用C语言模拟实现了一种解决方案。该方案的原理是:首先设置一个全局互斥量,当一个哲学家决定要拿筷子时,首先他要锁定该互斥量,这样其他哲学家就不能获得该互斥量,也就不能拿筷子。如果此时正好另一个哲学家锁定了该互斥量去拿两根筷子,那么该哲学家就等待另那个哲学家拿完筷子释放全局互斥量。然后去拿测试两边的哲学家是否在进餐,如果都没有进餐,那么那就可以拿到两根筷子,然后释放互斥量,自己进入吃饭状态。如果旁边有一个哲学家在进餐,那么他就释放互斥量,继续思考。
以下是C语言的具体实现,这是我个人的一点思考,如有不对的地方,欢迎指正探讨。
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#define N 5
#define LEFT (i-1+N)%N
#define RIGHT (i+1)%N
#define THINKING 0
#define EATING 1
int state[N];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutexattr_t attr;
void philosopher(i)
{
while (1)
{
think(i);
take_forks(i);
eat(i);
put_forks(i);
}
}
void take_forks(int i)
{
pthread_mutex_lock(&mutex);
test(i);
pthread_mutex_unlock(&mutex);
}
void put_forks(int i)
{
state[i] = THINKING;
}
void test(int i)
{
if(state[LEFT] != EATING && state[RIGHT] != EATING)
{
state[i] = EATING;
return 1;
}
return 0;
}
void eat(int i)
{
if(state[i] == EATING)
{ printf("philosopher %d is eating......./n", i);
sleep(5);
}
}
void think(int i)
{
if(state[i] == THINKING)
{ printf("philosopher %d is thinking......./n", i);
sleep(5);
}
}
int main()
{
int i = 0;
pthread_t id;
int ret;
for(i = 0; i < N ; i++)
{
ret=pthread_create(&id,NULL,(void *) philosopher, i);
if(ret!=0)
{
printf ("Create pthread error!/n");
return 1;
}
}
pthread_join(id,NULL);
}