- 姓名 陈悦凯
- 学号 201821121011
- 班级 计算1811
1. 选择哪一个问题
- 哲学家进餐问题
2. 给出伪代码
1 semaphore chopstick chopstick[5] = {1,1,1,1,1}; 2 3 do 4 { 5 //think 6 wait(chopstick[i]); 7 wait(chopstick[(i+1)%5]); 8 //eat 9 signal(chopstick[i]); 10 signal(chopstick[(i+1)%5]); 11 }while(true)
先拿左手边筷子,再拿右手边筷子,进餐完毕先放下左手筷子,再放下右手筷子,在这种情况下,可能出现死锁,当五个哲学家同时去取他左边的筷子,每人拿到一只筷子且不释放,即五个哲学家只得无限等待下去,引起死锁。
3. 给出完整代码
#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) { //int left = no; //int right = (no + 1) % 5; /*struct sembuf{ short sem_num;信号量的编号 short sem_op;信号量一次PV操作时加减的数值 short sem_flg;跟踪该信号量的修改情况 }; */ struct sembuf sb = {no,-1,0}; int ret; ret = semop(semid,&sb,1); if(ret < 0) { ERR_EXIT("资源不足"); } 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("资源释放错误"); } return ret; } //相当于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()); //srand(time(NULL)); for(;;) { /*这里采取的措施是当两把刀叉都可用的时候(即两种资源都满足的时候) //哲学家才能吃饭,这样不相邻的哲学家就可吃上饭 printf("哲学家%d正在思考\n",no); // 思考中 sleep(3); printf("哲学家%d饿了\n",no); // 感觉到饥饿 wait_for_2fork(no,semid);//拿到两把叉子才能吃饭 printf("哲学家%d正在吃饭\n",no); // 吃饭 sleep(3); free_2fork(no,semid);//释放两把叉子*/ //这段代码可能会造成死锁 int left = no; int right = (no + 1) % 5; printf("哲学家%d正在思考\n",no); // 思考中 sleep(3); printf("哲学家%d饿了\n",no); // 感觉到饥饿 wait_1fork(left,semid); // 拿起左叉子,现在是只要有一个资源,就申请 sleep(3); wait_1fork(right,semid); // 拿到右叉子 printf("哲学家%d正在吃饭\n",no); // 吃饭 sleep(3); free_1fork(left,semid); // 释放左叉子 free_1fork(right,semid); // 释放右叉子 } } 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; }
4. 运行结果并解释
哲学家同时拿起左边的筷子,形成死锁
5. 加分项
只有可以同时拿起两个筷子的时候,哲学家才选择拿起筷子,
代码:
//这里采取的措施是当两把刀叉都可用的时候(即两种资源都满足的时候) //哲学家才能吃饭,这样不相邻的哲学家就可吃上饭 printf("哲学家%d正在思考\n",no); // 思考中 sleep(3); printf("哲学家%d饿了\n",no); // 感觉到饥饿 wait_for_2fork(no,semid);//拿到两把叉子才能吃饭 printf("哲学家%d正在吃饭\n",no); // 吃饭 sleep(3); free_2fork(no,semid);//释放两把叉子
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); }