关于哲学家就餐问题的分析代码.
①总体思路:
都去拿左边的筷子,并且最后一个人不能去拿筷子(防止大家都拿了左边的筷子,没有右边的筷子,导致死锁了),解决死锁问题的办法就是同时只允许四位哲学家同时拿起同一边的筷子,这样就能保证一定会有一位哲学家能够拿起两根筷子完成进食并释放资源,供其他哲学家使用,从而实现永动,避免了死锁。举个最简单的栗子,假定0~3号哲学家已经拿起了他左边的筷子,然后当4号哲学家企图去拿他左边的筷子的时候,将该哲学家的线程锁住,使其拿不到其左边的筷子,然后其左边的筷子就可以被3号哲学家拿到,然后3号哲学家进餐,释放筷子,然后更多的哲学家拿到筷子并进餐。
如何才能实现当4号哲学家企图拿起其左边的筷子的时候将该哲学家的线程阻塞?这个时候就要用到该问题的提出者迪杰斯特拉(这货还提出了迪杰斯特拉最短路径算法,著名的银行家算法也是他发明的)提出的信号量机制。因为同时只允许有四位哲学家同时拿起左筷子,因此我们可以设置一个信号量r,使其初始值为4,然后每当一位哲学家企图去拿起他左边的筷子的时候,先对信号量做一次P操作,从而当第五位哲学家企图去拿做筷子的时候,对r做一次P操作,r = -1,由r < 0得第五位哲学家的线程被阻塞,从而不能拿起左筷子,因此也就避免了死锁问题。然后当哲学家放下他左边的筷子的时候,就对r做一次V操作。
②在主线程和子线程中,避免了竞争关系.
代码参考如下:
/*********************************** * @file linux_zexuejia.c * @copyright 月光下的脚步 Co.,Ltd.ALL Right Reserved * @brief 使用信号量和互斥锁完成,哲学家就餐问题。 * @author 王有康 * @data 2019、7、31 * @version V1.1 * @Last Modified 2018/10/25 wangyoukang * @note 当前版本是v1.1版本,以后需要修改,可以在上添加版本和修改日期 * @note * @warning * @Function List : ************************************/ #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> #define N 5 //互斥锁 pthread_mutex_t chops[N]; //信号量 sem_t r; /********************** * @fn philosopher * @biref 每次只有4个人能够获得左手资源,这样不会死锁 * @param philosopher number * @return * @other ***********************/ void philosopher(void *arg) { int i = *(int *)arg; int left = i; int right = (i + 1)%N; while(1) { printf("哲学家%d在思考问题\n",i); usleep(1000); printf("哲学家%d饿了\n",i); sem_wait(&r); pthread_mutex_lock(&chops[left]); printf("philosopher %d take left lock\n",i); pthread_mutex_lock(&chops[right]); printf("philosopher %d take right lock\n",i); printf("philosopher %d eat\n",i); usleep(1000); pthread_mutex_unlock(&chops[right]); printf("philosopher %d release right lock\n",i); pthread_mutex_unlock(&chops[left]); printf("philosopher %d realease left lock\n",i); sem_post(&r); } } /********************** * @fn philosopher * @biref 主函数 * @param * @return * @other ***********************/ int main(int argc,char **argv) { int i = 0,*ptr; pthread_t tid[N]; for(i = 0;i < N;i++) { pthread_mutex_init(&chops[i],NULL); } sem_init(&r,0,4); for(i = 0;i < N;i++) { //防止主线程和对等线程竞争,给线程和主线程分配不同的内存区域。其实这个地方和线程安全中的分配不同内存相似,可以看csapp线程安全 ptr = malloc(sizeof(int)); *ptr = i; pthread_create(&tid[i],NULL,(void *)philosopher,&i); } for( i = 0;i< N;i++) { pthread_join(tid[i],NULL); } for(i = 0;i < N;i++) { pthread_mutex_destroy(&chops[i]); } sem_destroy(&r); return 0; }