操作系统第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开吃。程序能一直跑,表示没有死锁。