问题:5个哲学家围坐在一个圆桌上,每两个哲学家之间都有一只筷子,哲学家平时进行思考,只有当他们饥饿时,才拿起筷子吃 饭。规定每个哲学家只能先取其左边筷子,然后取其右边筷子,然后才可以吃饭。
要求:使用线程锁、思考时间随机。
思路:定义数组表示五双筷子,1表示空闲状态,0表示使用状态。
int state[N] = {1,1,1,1,1};
在线程函数中,只需要循环进行吃饭、思考就好。问题在于如何拿放筷子。
while(1)
{
printf("哲学家%d在思考!!\n",id);
sleep(5);
take_forks(id);
printf("哲学家%d在吃饭~~\n",id);
sleep(2);
put_forks(id);
}
对于可能产生的死锁问题,我们采用当两边筷子同时空闲时取用。否则一直等待。
if(state[id]==1&&state[(id+1)%N]==1)
{
pthread_mutex_lock(&mutex);
state[id]=0;
state[(id+1)%N]=0;
pthread_mutex_unlock(&mutex);
}
else
;
最终代码:
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#define N 5 //定义哲学家数量为5人
int state[N] = {1,1,1,1,1}; //定义数组,用于表示五个筷子的使用情况,1代表空闲,0表示在使用
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; //定义线程锁,用于state变量的锁
void take_forks(int id) //拿起筷子函数
{
if(state[id]==1&&state[(id+1)%N]==1) //当左边筷子与右边筷子同时空闲时,拿起(置0)
{
pthread_mutex_lock(&mutex); //打开线程锁,使其他线程不能对state进行修改
state[id]=0;
state[(id+1)%N]=0;
pthread_mutex_unlock(&mutex); //释放线程锁,使其他线程可以对state进行修改
}
else //否则一直执行空指令,等待同时空闲状态
;
}
void put_forks(int id) //将左边筷子与右边筷子同时放下(置1)
{
pthread_mutex_lock(&mutex);
state[id]=1;
state[(id+1)%N]=1;
pthread_mutex_unlock(&mutex);
}
void *philosopher(void *arg) //线程执行函数
{
int id=*(int *)arg; //将哲学家编号,强制装换为int类型
srand( (unsigned)time( NULL ) ); //初始化随机数
while(1)
{
int time_s = rand()%5+1;
//int time_s = 5;
printf("哲学家%d在思考 %d秒!!\n",id,time_s); //思考5秒
sleep(time_s);
take_forks(id); //拿起筷子
printf("哲学家%d在吃饭~~\n",id); //吃饭2秒
sleep(2);
put_forks(id); //放下筷子继续思考
}
}
int main()
{
int i,id[N];
pthread_t phi[N]; //定义线程标识符数组
for(i=0;i<N;i++) //绑定线程函数
{
id[i]=i;
pthread_create(&phi[i],NULL,philosopher,(void *)&id[i]);
}
for(i=0;i<N;i++) //释放线程资源
{
pthread_join(phi[i],NULL);
}
return 0;
}
运行结果如下:
用于作为学习笔记,这是我们一次的嵌入式作业。能力有限,可能存在考虑不及的问题,望大神指点优化!
闲着没事,又尝试了其他的方法:
定义多个线程锁,使之作为哲学家所使用的筷子。
pthread_mutex_t mutex[N]={PTHREAD_MUTEX_INITIALIZER};
直接使之进行左右筷子的抢夺。
while(1)
{
//int time_s = rand()%5+1;
int time_s = 5;
printf("哲学家%d在思考 %d秒!!\n",id,time_s); //思考5秒
sleep(time_s);
pthread_mutex_lock(&mutex_flag);
pthread_mutex_lock(&mutex[(id+1)%N]);
printf("哲学家%d在吃饭~~\n",id); //吃饭2秒
sleep(2);
pthread_mutex_unlock(&mutex[id]);
pthread_mutex_unlock(&mutex[(id+1)%N]);
}
这又牵扯到了可能会产生死锁的问题。继续进行解决。
1、再加一把锁,使之每次只能一人进餐。
while(1)
{
//int time_s = rand()%5+1;
int time_s = 5;
printf("哲学家%d在思考 %d秒!!\n",id,time_s); //思考5秒
sleep(time_s);
pthread_mutex_lock(&mutex_flag);
pthread_mutex_lock(&mutex[id]);
pthread_mutex_lock(&mutex[(id+1)%N]);
printf("哲学家%d在吃饭~~\n",id); //吃饭2秒
sleep(2);
pthread_mutex_unlock(&mutex[id]);
pthread_mutex_unlock(&mutex[(id+1)%N]);
pthread_mutex_unlock(&mutex_flag);
}
这种方式的缺点很显然,就是每次只能有一人进餐。
运行结果如下:
2、最多允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释放出他所使用过的两支筷子,从而可使更多的哲学家进餐。
我们在全局加一个变量,flag使之表示正在占用筷子的人数。判断如果使用筷子的人数大于等于4时,便退出执行。
while(1)
{
//int time_s = rand()%5+1;
int time_s = 5;
printf("哲学家%d在思考 %d秒!!\n",id,time_s); //思考5秒
sleep(time_s);
if(flag >=4)
{
printf("falg >= 4\n");
continue;
}
pthread_mutex_lock(&mutex_flag); //用餐人数加一
flag++;
pthread_mutex_unlock(&mutex_flag);
pthread_mutex_lock(&mutex[id]);
pthread_mutex_lock(&mutex[(id+1)%N]);
printf("哲学家%d在吃饭~~\n",id); //吃饭2秒
sleep(2);
pthread_mutex_unlock(&mutex[id]);
pthread_mutex_unlock(&mutex[(id+1)%N]);
pthread_mutex_lock(&mutex_flag); //用餐人数减一
flag--;
pthread_mutex_unlock(&mutex_flag);
}
嗯,这种方法可行!