标签:
一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭,如图2-10所示。哲学家们倾注毕生精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿的时候,才试图拿起左、 右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿到了两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
1) 关系分析。5名哲学家与左右邻居对其中间筷子的访问是互斥关系。
2) 整理思路。显然这里有五个进程。本题的关键是如何让一个哲学家拿到左右两个筷子而不造成死锁或者饥饿现象。那么解决方法有两个,一个是让他们同时拿两个筷子;二是对每个哲学家的动作制定规则,避免饥饿或者死锁现象的发生。
#define left(phi_id) (phi_id+N-1)%N #define right(phi_id) (phi_id+1)%N N = 5
5支筷子对应5个互斥锁,所以:
pthread_mutex_t forks[N]={PTHREAD_MUTEX_INITIALIZER};
哲学家线程需要执行的动作是:
void take_forks(int id){ //获取左右两边的筷子 printf("Pil[%d], left[%d], right[%d]\n", id, left(id), right(id)); pthread_mutex_lock(&forks[left(id)]); pthread_mutex_lock(&forks[right(id)]); //printf("philosopher[%d] take_forks...\n", id); } void put_down_forks(int id){ printf("philosopher[%d] is put_down_forks...\n", id); pthread_mutex_unlock(&forks[left(id)]); pthread_mutex_unlock(&forks[right(id)]); } void* philosopher_work(void *arg){ int id = *(int*)arg; printf("philosopher init [%d] \n", id); while(1){ thinking(id); take_forks(id); eating(id); put_down_forks(id); } }
该算法存在以下问题:当五个哲学家都想要进餐,分别拿起他们左边筷子的时候(都恰好执行完
pthread_mutex_unlock(&forks[left(id)]);)
筷子已经被拿光了,等到他们再想拿右边的筷子的时候(执行
pthread_mutex_unlock(&forks[right(id)]);
)就全被阻塞了,这就出现了死锁。
为了防止死锁的发生,可以对哲学家进程施加一些限制条件,对哲学家顺序编号,当一个哲学家左右两边的筷子都可用时,才允许他抓起筷子。
void* philosopher_work(void *arg){ int id = *(int*)arg; printf("philosopher init [%d] \n", id); while(1){ thinking(id); pthread_mutex_lock(&mutex); take_forks(id); pthread_mutex_unlock(&mutex); eating(id); put_down_forks(id); } }
这个代码有个问题就是统一时间只能有一个哲学家取筷子,效率比较低.
全部的源码如下:
/************* * every philosopher is in while loop: thinking -> take_forks -> eating -> put_down_forks -> thingking * * 对于可能产生的死锁问题,我们这里采用一中解决的办法,那就是只有当哲学接的左右两只筷子均处于可用状态时, * 才允许他拿起筷子。这样就可以避免他们同时拿起筷子就餐,导致死锁。 * * 如果2号哲学家在吃饭那么1号和3号就必须是在思考. * * * * * ************/ #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #include <unistd.h> #define N 5 // five philosopher #define T_EAT 5 #define T_THINK 5 #define left(phi_id) (phi_id+N-1)%N #define right(phi_id) (phi_id+1)%N enum { think , hungry , eat }phi_state[N]; pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t forks[N]={PTHREAD_MUTEX_INITIALIZER}; void thinking(int id){ sleep(T_THINK); printf("philosopher[%d] is thinking...\n", id); } void eating(int id){ sleep(T_EAT); printf("philosopher[%d] is eating...\n", id); } void take_forks(int id){ //获取左右两边的筷子 printf("Pil[%d], left[%d], right[%d]\n", id, left(id), right(id)); pthread_mutex_lock(&forks[left(id)]); pthread_mutex_lock(&forks[right(id)]); //printf("philosopher[%d] take_forks...\n", id); } void put_down_forks(int id){ printf("philosopher[%d] is put_down_forks...\n", id); pthread_mutex_unlock(&forks[left(id)]); pthread_mutex_unlock(&forks[right(id)]); } void* philosopher_work(void *arg){ int id = *(int*)arg; printf("philosopher init [%d] \n", id); while(1){ thinking(id); pthread_mutex_lock(&mutex); take_forks(id); pthread_mutex_unlock(&mutex); eating(id); put_down_forks(id); } } int main(){ pthread_t phiTid[N]; int i; int err; int *id=(int *)malloc(sizeof(int)*N); for(i=0; i < N; ++i){ //printf("i ==%d\n", i); id[i] = i; err = pthread_create(&phiTid[i], NULL, philosopher_work, (void*)(&id[i])); //这种情况生成的thread id是0,1,2,3,4 if (err != 0) printf("can‘t create process for reader"); } while(1); return 0; }
标签:
原文地址:http://www.cnblogs.com/biglucky/p/4633706.html