操作系统第6次实验报告:使用信号量解决进程互斥访问
作者:互联网
- 姓名:杨富宏
- 学号:201821121017
- 班级:计算1811
1. 哲学家进餐问题
五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在桌子上有五只碗和五只筷子,他们的生活方式是交替地进行思考和进餐。
平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐毕,放下筷子继续思考。
2. 给出伪代码
void philosopher(int i) // i:哲学家编号,从0到4 { while(TRUE) { think(); // 哲学家思考 take_fork(i); //饿了,拿起左叉子 take_fork((i+1)%N); // 拿起右叉子 eat(); // 进食 put_fork(i); // 放下左叉子 put_fork((i+1)%N); // 放下右叉子 } }
可以保证不会有两个相邻的哲学家同时进餐,但却可能引起死锁的情况。假如五位哲学家同时饥饿而都拿起的左边的叉子,
就会使五个信号量fork都为0,当他们试图去拿右手边的叉子时,都将无叉子而陷入无限期的等待。因此出现了死锁问题。
解决:上面造成死锁是因为五个哲学家都拿起一边的叉子,而另一边的却没有拿到,继而一直等待着另外一边。
这样解决的办法就是哲学家必须同时拿起左右两边的叉子,这样可以保证每一次都有两个不相邻的哲学家同时进餐。
3. 给出完整代码
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<sys/ipc.h> 4 #include<sys/msg.h> 5 #include<sys/types.h> 6 #include<unistd.h> 7 #include<errno.h> 8 #include<sys/ipc.h> 9 #include<sys/sem.h> 10 #include<sys/wait.h> 11 12 #define SEMS_NUM 5 //信号量数目 13 #define THINKER_NUM 5 //哲学家人数 14 #define FORK_NUM 5 //叉子数 15 #define TIME_WAIT (rand() % 5 + 1) //等待时间 16 17 union semun 18 { 19 int val; //SETVAL用的值 20 struct semid_ds *buf; //IPC_STAT、IPC_SET用的semid_ds结构 21 unsigned short *array; //SETALL、GETALL用的数组值 22 struct seminfo *__buf; //为控制IPC_INFO提供的缓存 23 }; 24 25 #define ERR_EXIT(m) \ 26 do { \ 27 perror(m); \ 28 exit(EXIT_FAILURE); \ 29 } while(0) 30 31 void P(int sem_id,int left_fno,int right_fno) 32 { 33 struct sembuf sbuf[2] = 34 { 35 {left_fno, -1, SEM_UNDO}, 36 {right_fno, -1, SEM_UNDO} 37 }; 38 39 if(semop(sem_id, sbuf, 2) == -1) { 40 ERR_EXIT("P"); 41 } 42 } 43 /*对信号量数组编号为no的信号量做V操作 44 哲学家放回叉子 45 */ 46 void V(int sem_id,int left_fno,int right_fno){ 46 void V(int sem_id,int left_fno,int right_fno){ 47 48 /* 49 sbuf.sem_num:序号 50 sbuf.sem_op:操作,1表示V操作 51 sem_flg:设置信号量的操作 52 */ 53 struct sembuf sbuf[2] = 54 { 55 {left_fno, 1, SEM_UNDO}, 56 {right_fno, 1, SEM_UNDO} 57 }; 58 59 if(semop(sem_id, sbuf, 2) == -1) { 60 ERR_EXIT("V"); 61 } 62 } 63 void think(int tk_no){ 64 printf("Philosopher %d is thinking\n", tk_no); 65 sleep(TIME_WAIT); 66 } 67 68 void eat(int tk_no){ 69 printf("Philosopher %d is eating\n", tk_no); 70 sleep(TIME_WAIT); 71 } 72 73 void hungry(int tk_no){ 74 printf("Philosopher %d is hungry\n", tk_no); 75 } 76 77 void philosopere(int sem_id,int tk_no) 78 { 79 srand(getpid()); 80 int left_fno=tk_no; //left_fno左边叉子编号 81 int right_fno=(left_fno+1)%FORK_NUM; 82 while(1) 83 { 84 think(tk_no);//思考 85 hungry(tk_no);//饥饿 86 //拿取一双叉子 87 P(sem_id,left_fno,right_fno); 88 eat(tk_no);//就餐 89 //放下叉子 90 V(sem_id,left_fno,right_fno); 91 } 92 } 93 int main() 94 { 95 //1.创建 Semaphore(计数信号量) 96 //创建信号集,其中有SEMS_NUM个信号量 97 int sem_id = semget(IPC_PRIVATE, SEMS_NUM, IPC_CREAT | 0666); 98 if (sem_id == -1){ 99 ERR_EXIT("semget"); 100 } 101 102 //2.初始化 Semaphore 103 union semun sem; 104 sem.val = 1; 105 int i; 106 for (i = 0; i < SEMS_NUM; i++){ 107 if(semctl(sem_id, i, SETVAL, sem)==-1){ 108 ERR_EXIT("semctl"); 109 } 110 } 111 112 int tk_no = 0;//哲学家编号 113 pid_t pid; 114 //创建子进程 115 for (i = 1; i < THINKER_NUM; i++) 116 { 117 pid = fork(); 118 if (pid == -1){ 119 ERR_EXIT("fork"); 120 } 121 if (pid == 0){ 122 tk_no = i; 123 break; 124 } 125 } 126 127 philosopere(sem_id,tk_no);//处理就餐 128 129 return 0; 130 }
4. 运行结果并解释
结果解释:
本题有五个进程,对应着五个哲学家。首先哲学家进行思考,接着就是饥饿,最后哲学家同时拿起两边的叉子进餐,
每一轮只有两位哲学家能够进餐,另外三位需要等待,并且这两位哲学家不能相邻,实验结果中首先是一号和四号哲学
家先进餐,这两个哲学家并不相邻。结果表示哲学家的进餐过程没有停,解决了上面的死锁问题。
参考文献:https://blog.csdn.net/qq_28602957/article/details/53538329
标签:no,int,叉子,信号量,互斥,tk,fno,sem,实验报告 来源: https://www.cnblogs.com/yangfuhong/p/12989971.html