操作系统第6次实验报告:使用信号量解决进程互斥访问
姓名:张一鸣
学号:201821121050
班级:计算1812
一、实验目的
通过编程进一步了解信号量。
二、实验内容
在服务器上用Vim编写一个程序:使用信号量解决任一个经典PV问题,测试给出结果,并对解释运行结果。
- 生产者-消费者问题
- 读者-写者问题
- 哲学家进餐问题
三、实验报告
1. 选择哪一个问题
哲学家进餐问题
2. 给出伪代码
semaphore chop[5]; void main(){ chop[5]={1,1,1,1,1}; parbegin(Philosopher(i)(i=0...4)); } void Philosopher(i){ do{ thinking; wait(chop[i]); wait(chop[i+1]mod5); eating; signal(chop[i]); signal)chop[i+1]mod5); }while(1); }
为了避免死锁,仅当哲学家左右两侧的筷子都可用时,才允许他一次性同时拿起两只筷子。
semaphore chop[5]; void main(){ chop[5]={1,1,1,1,1}; parbegin(Philosopher(i)(i=0...4)); } void Philosopher(i) { do { thinking; Swait(chopstick[(i+1)]mod5,chop[i]); eating; Ssignal(chopstick[(i+1)]mod5,chop[i]); }while(1); }
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) { 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) 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} }; semop(semid,buf,2); } 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; 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); } 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. 运行结果并解释
五个哲学家的编号为0~4
一开始,所有哲学家都处于思考状态
3号哲学家饥饿,此时其左右两边的筷子均可用,于是3号哲学家开始进餐
2号哲学家饥饿,但由于3号哲学家拿走了其右手边的筷子并且没有释放,于是2号哲学家保持饥饿状态
1号哲学家饥饿,此时其左右两边的筷子均可用,于是1号哲学家开始进餐
......