五個哲學家圍在一個圓桌就餐,每一個人都必須拿起左右兩把叉子才能進餐,當每一個人都先拿起左叉子,等待右叉子的時候就會形成死鎖。spa
假設哲學家的編號是A、B、C、D、E,叉子編號是一、二、三、四、5,哲學家和筷子圍成一圈以下圖所示:.net
哲學家飢餓時,老是先去拿他左邊的筷子,即執行wait(chopstick);成功後,再去拿他右邊的筷子,即執行wait(chopstick[(i+ 1) mod 51]);code
再成功後即可進餐.進餐完畢,又先放下他左邊的筷子,而後放下他右邊的筷子.blog
emaphore chopstick chopstick[5] = {1,1,1,1,1}; do { //思考 wait(chopstick[i]); wait(chopstick[(i+1)%5]); //進餐 signal(chopstick[i]); signal(chopstick[(i+1)%5]); }while(true)
雖然上述解法可保證不會有兩個相臨的哲學家同時進餐但起死鎖是可能的.假如五個哲學家同時飢餓而各自拿起右邊的筷子時,就會使五個信號量chopstick均爲0;索引
當他們試圖去拿右邊的筷子時,都將因無筷子可拿而無限期地等待.對於這樣的死鎖問題可按照以下修改。進程
semaphore chopstick chopstick[5] = {1,1,1,1,1}; do { //think Sswait(chopstick[i],chopstick[(i+1)%5]); //eat Ssignal(chopstick[i],chopstick[(i+1)%5]); }while(true)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/wait.h> union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) //申請一個資源 int wait_1fork(int no,int semid) { struct sembuf sb = {no,-1,0}; int ret; ret = semop(semid,&sb,1); if(ret < 0) { ERR_EXIT("semop"); } return ret; } // 釋放一個資源 int free_1fork(int no,int semid) { struct sembuf sb = {no,1,0}; int ret; ret = semop(semid,&sb,1); if(ret < 0) { ERR_EXIT("semop"); } return ret; } //這裏代表叉子是一個臨界資源 #define DELAY (rand() % 5 + 1) //至關於P操做 void wait_for_2fork(int no,int semid) { //哲學家左邊的刀叉編號和哲學家是同樣的 int left = no; //右邊的刀叉 int right = (no + 1) % 5; //刀叉值是兩個 //注意第一個參數是編號 //操做的是兩個信號量,即兩種資源都知足,才進行操做 struct sembuf buf[2] = { {left,-1,0}, {right,-1,0} }; //信號集中有5個信號量,只是對其中的資源sembuf進行操做 semop(semid,buf,2); } //至關於V操做 ,釋放刀叉 void free_2fork(int no,int semid) { int left = no; int right = (no + 1) % 5; struct sembuf buf[2] = { {left,1,0}, {right,1,0} }; semop(semid,buf,2); } //哲學家要作的事 void philosophere(int no,int semid) { srand(getpid()); for(;;) { #if 1 //這裏採起的措施是當兩把刀叉均可用的時候(即兩種資源都知足的時候) //哲學家才能吃飯,這樣不相鄰的哲學家就可吃上飯 printf("%d is thinking\n",no); // 思考中 sleep(DELAY); printf("%d is hungry\n",no); // 感受到飢餓 wait_for_2fork(no,semid);//拿到兩把叉子才能吃飯 printf("%d is eating\n",no); // 吃飯 sleep(DELAY); free_2fork(no,semid);//釋放兩把叉子 #else //這段代碼可能會形成死鎖 int left = no; int right = (no + 1) % 5; printf("%d is thinking\n",no); // 思考中 sleep(DELAY); printf("%d is hungry\n",no); // 感受到飢餓 wait_1fork(left,semid); // 拿起左叉子,如今是隻要有一個資源,就申請 sleep(DELAY); wait_1fork(right,semid); // 拿到右叉子 printf("%d is eating\n",no); // 吃飯 sleep(DELAY); free_1fork(left,semid); // 釋放左叉子 free_1fork(right,semid); // 釋放右叉子 #endif } } int main(int argc,char *argv[]) { int semid; //建立信號量 //信號量集中5個信號量 semid = semget(IPC_PRIVATE,5,IPC_CREAT | 0666); if(semid < 0) { ERR_EXIT("semid"); } union semun su; su.val = 1; int i; for(i = 0;i < 5;++i) { //注意第二個參數也是索引 semctl(semid,i,SETVAL,su); } //建立4個子進程 int num = 0; pid_t pid; for(i = 1;i < 5;++i) { pid = fork(); if(pid < 0) { ERR_EXIT("fork"); } if(0 == pid) // 子進程 { num = i; break; } } //這裏就是哲學家要作的事情 philosophere(num,semid); return 0; }
結果解釋:ip
在結果中能夠觀察到就餐過程一直執行沒有中止,說明沒有發生死鎖現象。資源
【1】https://blog.csdn.net/u014304293/article/details/46004677get