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

  • 姓名:蒋浩天
  • 学号:201821121024
  • 班级:计算1811

1. 选择哪一个问题

哲学家进餐问题

2. 给出伪代码

思路:针对哲学家进餐问题,对哲学家编号1-4,对叉子编号1-4,假设哲学家进餐总是先拿起左手边的叉子再拿右手边的叉子。如果让哲学家自由一次取一根叉子,那么会出现所有哲学家都拿起左边叉子并且等待右边叉子的锁死情况。所以为解决这种锁死情况,规定哲学家只有在两边叉子都闲置的前提下才能拿起两叉子吃饭,否则处于等待状态。

int main(){
    int i=0;
    while(true){
        哲学家(i);
        i=(i+1)%5 
    }
    
}
void 哲学家(i){
    if(左右叉子在手里){
        放下叉; 
    }
    else if(左右叉子闲置){
        拿起叉子吃饭; 
    }
    else{//有叉子不空闲 
        等待; 
    }
} 

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>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

 
#define DELAY (rand() % 5 + 1) //给一个时延,做停顿 
 
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};
  
void wait_pick(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);//信号集中有5个信号量,只资源sembuf进行操作
}
 
void free_fork(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)//哲学家(i)
{
    srand(getpid());
    for(;;) 
    {
        printf("philosopher:%d is thinking\n",no);  // 思考中
        sleep(DELAY);
        printf("philosopher:%d is hungry\n",no);  // 感觉到饥饿
        wait_pick(no,semid);                     //两把叉子闲置,才能拿起吃饭 
        printf("philosopher:%d is eating\n",no);  // 吃饭
        sleep(DELAY);
        free_fork(no,semid);//释放两把叉子
    }
}
 
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);
    }
    //创建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);   //哲学家(i)
    return 0;
}

4. 运行结果并解释

 

 运行结果可以一直进行下去,我只截取了部分,说明没有出现死锁现象。

在伪代码设计思路中有提到,针对可能出现的五位哲学家都拿起左边叉子,等不到右边叉子而陷入死锁的情况,我采用哲学家等左右两侧叉子都闲置的情况下拿起叉子吃饭的解决方案,这样可以使这种死锁情况不发生。

 

posted @ 2020-05-31 02:15  HaotianJiang  阅读(199)  评论(0编辑  收藏  举报