操作系统第6次实验报告:使用信号量解决进程互斥访问

姓名:李冠毅 学号:201822121031 班级:计算1811

目录
  • 一、实验目的
  • 二、实验内容
  • 三、实验报告
    • 1. 选择哪一个问题
    • 2. 给出伪代码
    • 3. 给出完整代码
    • 4. 运行结果并解释

一、实验目的

通过编程进一步了解信号量。

二、实验内容

在服务器上用Vim编写一个程序:使用信号量解决任一个经典PV问题,测试给出结果,并对解释运行结果。

  • 生产者-消费者问题
  • 读者-写者问题
  • 哲学家进餐问题

三、实验报告

1. 选择哪一个问题

选题哪个问题?

  • 生产者-消费者问题
  • 读者-写者问题
  • 哲学家进餐问题(√)

详细问题如下:

  有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。

2. 给出伪代码

3. 给出完整代码

由于在服务器vim查看注释出现乱码,这里不截图直接贴源码了


#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("%d thinking\n",no); sleep(DELAY);//思考
printf("%d hungry\n",no); //饥饿
wait_for_2fork(no,semid); //空出两个资源开吃
printf("%d eating\n",no); sleep(DELAY);//开饭
free_2fork(no,semid); //吃完释放两个资源
#else
int left = no;
int right = (no + 1) % 5;
printf("%d thinking\n",no); sleep(DELAY); //思考
printf("%d hungry\n",no); //饥饿
wait_1fork(left,semid); sleep(DELAY); //只要空出一个资源就能吃
wait_1fork(right,semid); //拿到右边
printf("%d eating\n",no); sleep(DELAY); //开饭
free_1fork(left,semid); // 释放左边
free_1fork(right,semid); // 释放右边
#endif
}
}


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); //第二个参数同是索引
}
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. 运行结果并解释

  一开始(0.4.3.2.1)5人都在思考,4饿了开吃,3因为4再吃饿着,1饿了开吃,0饿了因为1再吃饿着,2饿了因为1再吃饿着,4吃完开始思考,所以3开吃,1吃完开始思考,所以0开吃,4饿了因为0再吃饿着,3吃完开始思考,所以2开吃,0吃完开始思考所以4开吃,1饿了因为2再吃饿着,3饿了因为4再吃饿着,4吃完开始思考,2也吃完开始思考,所以3开吃。程序能一直跑,表示没有死锁。