操作系统第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个叉子的情况下,一次最多只能有两人同时开饭。

 

posted on 2020-05-31 01:05  xudeyang  阅读(181)  评论(0编辑  收藏  举报