问题描述:
5 个哲学家用一生的时间吃饭和思考。他们共用一张圆桌,每人都有一张椅 子,桌上放着 5 支筷子。每个哲学家感到饥饿时,会试图拿起左右的两只筷子, 每位哲学家每次只能拿起一只筷子。当每位哲学家同时有两支筷子的时候,他可 以吃饭。当他吃完后,他会放下筷子,并开始思考。
实验内容
- 根据哲学家进程间的相互制约关系,设置合理的信号量及信号量初值。
- 创建 5 个线程,分别模拟 5 个哲学家进程。
- 在哲学家线程之间通过对信号量的 P,V 操作,实现线程之间的同步关系。
解决方案
- 仅当哲学家左右手筷子都拿起时,才能进餐
- 规定奇数好哲学家先拿左手筷子,再拿右手筷子;而偶数号哲学家相反
- 最多允许 4 位哲学家同时去拿左筷子,最终能保证至少有一位哲学家能 进餐,并在用完后释放两只筷子供其他人使用。
- 此次实验代码采用第一种解决方式
实验步骤
设置哲学家就餐状态\ #define N 5 //哲学家数量
#define LEFT (i+N-1)%N //第 i 位哲学家的左边 筷子 #define RIGHT (i)%N //第 i 位哲学家的右边筷子
//哲学家状态 int state[N];
#define STATE_THINKING 11
//思考 #define STATE_EATING 12
//吃饭 #define STATE_HUNGRY 13
//饥饿 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER, s[N]; //信号量 筷子的信号量
检查哲学家的状态函数,并对其进行相应操作
如思考、吃饭以及饥饿 void checkState(int i) { …… }
具体代码
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <pthread.h>
#include <errno.h>
#include <math.h>
#define N 5 //哲学家数量
#define LEFT (i+N-1)%N //第i位哲学家的左边
#define RIGHT (i)%N //第i位哲学家的右边
int state[N]; //哲学家状态
#define STATE_THINKING 0 //思考
#define STATE_EATTING 1 //饭
#define STATE_HUNGRY 2 //
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER, s[N]; //两个信号量 这两个信号量代表的内容分别是 哲学家状态信号量/筷子信号量
int takeForks(int i)//检查哲学家的状态,并根据状态进行相应操作
{
pthread_mutex_lock(&s[LEFT]); //对左筷子上锁(哲学家拿起左边筷子)
if (pthread_mutex_trylock(&s[RIGHT]) == EBUSY) //如果右边筷子不可拿
{
pthread_mutex_unlock(&s[LEFT]); //释放左筷子
pthread_mutex_lock(&mutex); //更改状态
state[i]=STATE_HUNGRY; //无法申请筷子,饥饿状态下等待
pthread_mutex_unlock(&mutex);
return 0;
}
else
{
// printf("philosopher %d get the %d chopstick\n",i,i);
pthread_mutex_lock(&mutex);
state[i]=STATE_EATTING; //两只筷子都拿到,更改状态
pthread_mutex_unlock(&mutex);
return 1;
}
}
void putForks(int i)//放下左右筷子,并更改状态到思考
{
pthread_mutex_unlock(&s[LEFT]);
// printf("philosopher %d realse the %d chopstick\n",i,LEFT);
pthread_mutex_unlock(&s[RIGHT]);
// printf("philosopher %d realse the %d chopstick\n",i,i);
pthread_mutex_lock(&mutex);
state[i]=STATE_THINKING;
pthread_mutex_unlock(&mutex);
}
void think(int i) //思考完毕后更改状态为饥饿
{
printf("哲学家 %d 正在思考......\n",i);
sleep(1);
pthread_mutex_lock(&mutex);
state[i]=STATE_HUNGRY;
pthread_mutex_unlock(&mutex);
}
void eat(int i) //吃饭完毕后放筷子
{
printf("哲学家 %d 正在吃饭.....\n",i);
sleep(1);
putForks(i);
}
//检查哲学家的状态,如思考、吃饭以及饥饿,并进行相应操作
void checkState(int i)
{
switch(state[i]){
case STATE_EATTING:
eat(i);
break;
case STATE_THINKING:
think(i);
break;
case STATE_HUNGRY: //如果
takeForks(i);
break;
default:
printf("哲学家%d状态出错!\n",i);
break;
}
}
//哲学家线程的创建,包括思考、进餐等内容的设置
void* Philosopher(void *vargp)
{
int i = *(int*)vargp;
state[i]=STATE_THINKING;//初始化为思考状态
int j = 0;
while(1)
{
//printf("%d ",i);
checkState(i); //不停检查哲学家状态
}
return NULL;
}
int main()
{
int ar[N],i;
pthread_t thread_id[N];
for (i = 0; i < N; i++)
pthread_mutex_init(&s[i],NULL);
//创建5个线程表示五个哲学家
for(i=0;i<N;i++)
{
ar[i]=i;
pthread_create(&thread_id[i],NULL,(void*)Philosopher,&ar[i]);//创建进程函数
}
for(i=0;i<N;i++)
{
//等待子进程结束,才退出主进程
pthread_join(thread_id[i],NULL);
}
return 0;
}