五个哲学家围在一个圆桌就餐,每一个人都必须拿起左右两把叉子才能进餐,当每一个人都先拿起左叉子,等待右叉子的时候就会形成死锁。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