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

姓名:张皓落

学号:201821121005

班级:计算1811

1. 选择哪一个问题

  哲学家进餐问题具体描述:

假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。

2. 给出伪代码  

采用解决死锁的方法:

  哲学家手中刀叉的情况只有两种即没有或者有两个,仅当一个哲学家左右两边的叉子都可用时才允许他抓起叉子。那么哲学家就有三种状态:思考状态不用叉子、饥饿状态在等待左右叉子,吃饭状态正在使用两个叉子。

采用AND信号量实现:

semaphore  chopstick chopstick[5] = {1,1,1,1,1};

  for(;;){

        //think;     //哲学家思考中
        Sswait(chopstick[i],chopstick[(i+1)%5]);  //拿起左右刀叉
        //eat;     //哲学家吃饭中
        Ssignal(chopstick[i],chopstick[(i+1)%5]);   //释放左右刀叉
    }

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)
//将叉子设置为一个临界资源

#define DELAY (rand() % 5 + 1)

/*拿起两边的刀叉
采用的方法:仅当一个哲学家左右两边的叉子都可用时才允许他抓起叉子
哲学家才能吃饭,这样不相邻的哲学家就可吃上饭*/
void P(int no,int semid)
{
//哲学家左边的刀叉编号和哲学家是一样的
int left = no;
//右边的刀叉
int right = (no + 1) % 5;

//刀叉值是两个
//注意第一个参数是编号
//操作的是两个信号量,即同时拥有左右两个刀叉才可以吃饭
struct sembuf buf[2] = {
{left,-1,0},
{right,-1,0}
};
//信号集中有5个信号量,只是对其中的资源sembuf进行操作
semop(semid,buf,2);
}

//释放刀叉
void V(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(;;)
{
printf("第%d位哲学家正在思考\n",no);
sleep(DELAY);
printf("第%d位哲学家等待左右刀叉中\n",no); //饥饿状态
P(no,semid);//拿到两把叉子才能吃饭
printf("第%d位哲学家吃饭中\n",no); // 吃饭
sleep(DELAY);
V(no,semid);//释放两把叉子
}
}
int main(int argc,char *argv[])
{
int semid;
//创建5个信号量代表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);
}
//创建4个子进程
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. 运行结果并解释

运行结果(部分):

 

 

 解释:在一开始的时候,所有的哲学家都在思考中,没有人拿起刀叉,随后哲学家第4位(实际为第5位,哲学家编号从0开始)饥饿并且等待刀叉中,由于之前大家都在思考所第4位哲学家左右刀叉均可用随后其开始吃饭,第0位哲学家由于第4位哲学家拿走其右手边的刀叉并且没有释放导致其无法吃饭,第1位哲学家左右刀叉均可用亦进入吃饭中,第3位哲学家由于第4位哲学家拿走其左手边的刀叉并且没有释放导致其无法吃饭,这时第1位哲学家进入思考中释放刀叉,第2位哲学家右手边的刀叉被第1位哲学家释放即第二位哲学家进入吃饭状态......

注:该截图仅为运行结果的一部分,实际中一直在产生状态输出,没有产生死锁的状态。

posted @ 2020-05-29 12:59  现世安稳  阅读(208)  评论(0编辑  收藏  举报