哲学家就餐问题是计算机操作系统课程中一定会拿来作为死锁教材的经典案例。问题描述如下:哲学家吃饭问题:哲学家聚在一起吃饭,假定哲学家人数是五,这五个哲学家坐在一张圆桌上面,每个哲学家的左手旁边都放有一个叉子(fork),那么,这围城一圈的五个哲学家有五个叉子。每个哲学家有三种状态,thinking(思考),trying(尝试去拿叉子吃饭),eating(已经拿起叉子,正在吃饭)。每次吃饭需要两个叉子,也就是哲学家左右手边的叉子。如图1所示。
哲学家吃饭需要两个叉子(吼吼)。
图1
本实验采用了两种解决死锁的机制:
- 通过定时器(Timer)检测死锁,一旦发生死锁,就将哲学家恢复到初始的状态,然后使得哲学家和叉子的状态恢复到初始状态。
- 通过外部中断解决死锁,一旦发生死锁问题,通过外部中断,将哲学家恢复到初始的状态,然后使得哲学家和叉子的状态恢复到初始状态。
定时器(Timer)代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <stdlib.h> 4 #include <sys/wait.h>//为了使用sleep()函数 5 #include <unistd.h> 6 #include <signal.h>//为了产生中断 7 8 //哲学家的数目 9 int Number; 10 11 //声明共享变量fork,其中fork的数目和哲学家数目是相同的 12 struct Fork{ 13 int i;//只有0和1两个值,0代表不能被拿起来,1代表可以被拿起来 14 }; 15 struct Fork *myfork; 16 17 //定义一个philosopher的三个状态 18 #define Thinking 1 19 #define Trying 2 20 #define Eating 3 21 22 struct State{ 23 int sta; 24 int left; 25 int right; 26 }; 27 struct State *state; 28 29 void *EatMeal(); 30 31 32 int totalnumber; 33 void DetectLock(int); 34 void Sig_hander(int); 35 36 //得到参数 37 void GetArg( 38 char* argv[] /*in*/, 39 int* number /*out*/ 40 ); 41 //统计处于tring状态的哲学家的个数 42 int tryingNo; 43 44 //拿起叉子 45 int take_Fork(int i); 46 //放下叉子 47 void put_Fork(int i); 48 49 void main(int argc, char* argv[]) 50 { 51 GetArg(argv, &Number); 52 myfork = (struct Fork *)malloc(Number*sizeof(struct Fork)); 53 state = malloc(Number*sizeof(struct State)); 54 55 tryingNo = 0; 56 //声明进程数组,每一个进程代表一个哲学家 57 pthread_t philosopher[Number]; 58 pthread_t deadLockDetecter; 59 totalnumber = Number; 60 /*初始化每个哲学家的状态*/ 61 int t =0; 62 for(t=0; t< Number; t++) 63 { 64 state[t].sta = Thinking; 65 state[t].left = 0; 66 state[t].right = 0; 67 } 68 69 /*初始化每个勺子是可以使用的*/ 70 int k =0; 71 for(k=0; k<Number; k++) 72 { 73 myfork[k].i = 1; 74 } 75 76 int i; 77 //创建和哲学家数量想对应的进程,并且每个进程开始进行吃饭的活动 78 for( i = 0; i < Number; i++) 79 { 80 //记录当前进程的编号,并传递到Meal()函数中 81 int j = i; 82 pthread_create(&philosopher[i], NULL, EatMeal, &j); 83 printf("I am philosopher %d\n", j); 84 } 85 86 //int k = Number; 87 pthread_create(&deadLockDetecter,NULL, DetectLock,&k); 88 89 //将所有的进程进行Join操作。 90 for( i=0; i < Number; i++) 91 { 92 pthread_join(philosopher[i], NULL); 93 } 94 95 //退出程序 96 pthread_exit(0); 97 98 return ; 99 100 } 101 102 void *EatMeal(int *i) 103 { 104 //记录当前的线程id号 105 int id = *i; 106 107 108 state[id].sta = Thinking; //线程初始化的时候为Thinking 109 110 int leftFork = (id + Number) % Number; 111 int rightFork = (id + Number +1) % Number; 112 113 int mealTime = 5; 114 int mymealTime = 0; 115 while (mymealTime < mealTime) //每个philosopher必须吃得符合规定 116 { 117 if(state[id].sta == Thinking) 118 { 119 sleep(3); 120 state[id].sta = Trying; 121 }else if(state[id].sta == Trying) 122 { 123 124 // sleep(1); 125 if (take_Fork(leftFork)) 126 { 127 myfork[leftFork].i = 0; 128 state[id].left = 1; //自己标识左边的叉子被自己拿到 129 // printf("Phi %d takes left\n",id); 130 } 131 if(take_Fork(rightFork)) 132 { 133 myfork[rightFork].i = 0; 134 state[id].right = 1; //自己标识一下右边的叉子被自己拿到 135 // printf("Phi %d takes right\n",id); 136 } 137 138 printf("Philosopher %d is Trying\n", id); 139 sleep(3); 140 if(!take_Fork(leftFork)&&!take_Fork(rightFork)&&state[id].left==1&& state[id].right==1) 141 { 142 state[id].sta = Eating; 143 } 144 } 145 else 146 { 147 printf("Philosopher %d is Eating\n", id); 148 sleep(3); 149 state[id].left=0; 150 state[id].right=0; 151 state[id].sta = Thinking; 152 put_Fork(leftFork); 153 put_Fork(rightFork); 154 mymealTime++; 155 156 } 157 } 158 159 } 160 161 int take_Fork(int forkid) 162 { 163 if(myfork[forkid].i==0) return 0; 164 else 165 { 166 //myfork[forkid].i = 0; 167 return 1; 168 } 169 } 170 171 void put_Fork(int forkid) 172 { 173 if(myfork[forkid].i==0) 174 { 175 myfork[forkid].i=1; 176 } 177 } 178 179 void GetArg( 180 char * argv[], 181 int* number 182 ) 183 { 184 *number = strtol(argv[1], NULL, 10); 185 } 186 187 void DetectLock( 188 int k) 189 { 190 signal(SIGALRM, Sig_hander); 191 alarm(1); 192 while(1) pause(); 193 } 194 195 void Sig_hander(int sig) 196 { 197 int k = totalnumber;//获取人数 198 int flag = 1; 199 int i = 0; 200 for(i=0; i<k; i++) 201 { 202 if(state[i].sta != Trying) 203 { 204 flag = 0; 205 } 206 } 207 if(flag == 1) 208 { 209 printf("I am timer that dealing with deadlock\n"); 210 int m = 0; 211 for(m=0; m<k; m++) 212 { 213 state[m].sta = Thinking; 214 state[m].left = 0; 215 state[m].right = 0; 216 myfork[m].i = 1; 217 } 218 } 219 220 221 alarm(1); 222 return; 223 224 225 }
外部中断代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <stdlib.h> 4 #include <sys/wait.h>//为了使用sleep()函数 5 #include <unistd.h> 6 #include <signal.h>//为了产生中断 7 8 //哲学家的数目 9 int Number; 10 11 //声明共享变量fork,其中fork的数目和哲学家数目是相同的 12 struct Fork{ 13 int i;//只有0和1两个值,0代表不能被拿起来,1代表可以被拿起来 14 }; 15 struct Fork *myfork; 16 17 //定义一个philosopher的三个状态 18 #define Thinking 1 19 #define Trying 2 20 #define Eating 3 21 22 struct State{ 23 int sta; 24 int left; 25 int right; 26 }; 27 struct State *state; 28 29 void *EatMeal(); 30 31 32 int totalnumber; 33 void DetectLock(int); 34 void Sig_hander(int); 35 36 //得到参数 37 void GetArg( 38 char* argv[] /*in*/, 39 int* number /*out*/ 40 ); 41 //统计处于tring状态的哲学家的个数 42 int tryingNo; 43 44 //拿起叉子 45 int take_Fork(int i); 46 //放下叉子 47 void put_Fork(int i); 48 49 void main(int argc, char* argv[]) 50 { 51 GetArg(argv, &Number); 52 myfork = (struct Fork *)malloc(Number*sizeof(struct Fork)); 53 state = malloc(Number*sizeof(struct State)); 54 55 tryingNo = 0; 56 //声明进程数组,每一个进程代表一个哲学家 57 pthread_t philosopher[Number]; 58 pthread_t deadLockDetecter; 59 totalnumber = Number; 60 /*初始化每个哲学家的状态*/ 61 int t =0; 62 for(t=0; t< Number; t++) 63 { 64 state[t].sta = Thinking; 65 state[t].left = 0; 66 state[t].right = 0; 67 } 68 69 /*初始化每个勺子是可以使用的*/ 70 int k =0; 71 for(k=0; k<Number; k++) 72 { 73 myfork[k].i = 1; 74 } 75 76 int i; 77 //创建和哲学家数量想对应的进程,并且每个进程开始进行吃饭的活动 78 for( i = 0; i < Number; i++) 79 { 80 //记录当前进程的编号,并传递到Meal()函数中 81 int j = i; 82 pthread_create(&philosopher[i], NULL, EatMeal, &j); 83 printf("I am philosopher %d\n", j); 84 } 85 86 //int k = Number; 87 pthread_create(&deadLockDetecter,NULL, DetectLock,&k); 88 89 //将所有的进程进行Join操作。 90 for( i=0; i < Number; i++) 91 { 92 pthread_join(philosopher[i], NULL); 93 } 94 95 //退出程序 96 pthread_exit(0); 97 98 return ; 99 100 } 101 102 void *EatMeal(int *i) 103 { 104 //记录当前的线程id号 105 int id = *i; 106 107 108 state[id].sta = Thinking; //线程初始化的时候为Thinking 109 110 int leftFork = (id + Number) % Number; 111 int rightFork = (id + Number +1) % Number; 112 113 int mealTime = 5; 114 int mymealTime = 0; 115 while (mymealTime < mealTime) //每个philosopher必须吃得符合规定 116 { 117 if(state[id].sta == Thinking) 118 { 119 sleep(3); 120 state[id].sta = Trying; 121 }else if(state[id].sta == Trying) 122 { 123 124 // sleep(1); 125 if (take_Fork(leftFork)) 126 { 127 myfork[leftFork].i = 0; 128 state[id].left = 1; //自己标识左边的叉子被自己拿到 129 // printf("Phi %d takes left\n",id); 130 } 131 if(take_Fork(rightFork)) 132 { 133 myfork[rightFork].i = 0; 134 state[id].right = 1; //自己标识一下右边的叉子被自己拿到 135 // printf("Phi %d takes right\n",id); 136 } 137 138 printf("Philosopher %d is Trying\n", id); 139 sleep(3); 140 if(!take_Fork(leftFork)&&!take_Fork(rightFork)&&state[id].left==1&& state[id].right==1) 141 { 142 state[id].sta = Eating; 143 } 144 } 145 else 146 { 147 printf("Philosopher %d is Eating\n", id); 148 sleep(3); 149 state[id].left=0; 150 state[id].right=0; 151 state[id].sta = Thinking; 152 put_Fork(leftFork); 153 put_Fork(rightFork); 154 mymealTime++; 155 156 } 157 } 158 159 } 160 161 int take_Fork(int forkid) 162 { 163 if(myfork[forkid].i==0) return 0; 164 else 165 { 166 //myfork[forkid].i = 0; 167 return 1; 168 } 169 } 170 171 void put_Fork(int forkid) 172 { 173 if(myfork[forkid].i==0) 174 { 175 myfork[forkid].i=1; 176 } 177 } 178 179 void GetArg( 180 char * argv[], 181 int* number 182 ) 183 { 184 *number = strtol(argv[1], NULL, 10); 185 } 186 187 void DetectLock( 188 int k) 189 { 190 signal(SIGINT, Sig_hander); 191 sleep(10); 192 return ; 193 } 194 195 void Sig_hander(int sig) 196 { 197 int k = totalnumber;//获取人数 198 int flag = 1; 199 int i = 0; 200 for(i=0; i<k; i++) 201 { 202 if(state[i].sta != Trying) 203 { 204 flag = 0; 205 } 206 } 207 if(flag == 1) 208 { 209 printf("I am timer that dealing with deadlock\n"); 210 int m = 0; 211 for(m=0; m<k; m++) 212 { 213 state[m].sta = Thinking; 214 state[m].left = 0; 215 state[m].right = 0; 216 myfork[m].i = 1; 217 } 218 } 219 220 return; 221 222 223 }
Post Analysis:
将中断注册到了一个线程中,没有把其写入大主线程中。好吧,这个被老师给黑了。扣分到底!