操作系统第6次实验报告:使用信号量解决进程互斥访问
- 姓名:许德阳
- 学号:201821121045
- 班级:计算1812
1. 选择哪一个问题
哲学家进餐问题:
五个哲学家从p0到p5围坐在一个圆桌上,进行思考和吃饭,需要两把叉子才能吃饭,
每个人都先拿起左手边的叉子,在要拿右手边叉子的时候就会进入死循环。
2. 给出伪代码
每个哲学家可用以下伪代码表示:
semaphore chopstick[5]={1,1,1,1,1}; do { Sswait(chopstick[i],chopstick[(i+1)%5]); Ssignal(chopstick[i],chopstick[i+1)%5]); } while(1)
3. 给出完整代码
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <errno.h> #include <string.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/ipc.h> #include <sys/sem.h> #include <unistd.h> #include <sys/types.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){//相当于P操作 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("p%d 正在思考\n",no); sleep(DELAY);//思考 printf("p%d 开始饿了\n",no); //饥饿 wait_for_2fork(no,semid); //空出两个资源开吃 printf("p%d 开饭\n",no); sleep(DELAY);//开饭 free_2fork(no,semid); //吃完释放两个资源 #else int left = no; int right = (no + 1) % 5; printf("p%d 正在思考\n",no); sleep(DELAY); //思考 printf("p%d 开始饿了\n",no); //饥饿 wait_1fork(left,semid); sleep(DELAY); //只要空出一个资源就能吃 wait_1fork(right,semid); //拿到右边 printf("p%d 开饭\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); //创建集中5个信号量信号量 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){//创建4个子进程 pid = fork(); if(pid < 0) { ERR_EXIT("fork"); }if(0 == pid){ // 子进程 num = i; break; } }philosophere(num,semid);//哲学家开始 return 0; }
4. 运行结果
五个进程p0到p5表示5个哲学家,在一开始所有哲学家进入思考状态,突然有一个哲学家饿了,这里举例,p2饿了,于是p2开饭了,之后又结束开饭进入思考,
而p0开饭,p3也开饭,但随后又进入思考,通过观察5个哲学家在只有5个叉子的情况下,一次最多只能有两人同时开饭。