zoukankan      html  css  js  c++  java
  • 操作系统第6次实验报告:使用信号量解决进程互斥访问

    • 姓名:吕煜华
    • 学号:201821121046
    • 班级:计算1812

    1. 选择哪一个问题

    • 哲学家进餐问题
    有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。
    约束条件:
    (1)只有拿到两只筷子时,哲学家才能吃饭。
    (2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
    (3)任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子。

    2. 给出伪代码

    使用一个信号量表示一只筷子,由这五个信号量构成信号量数组,放在圆桌上的筷子是临界资源,在一段时间内只允许一位哲学家的使用。为了实现对筷子的互斥访问,5支筷子分别设置为为初始值为1的互斥信号量:

    semaphore chopstick[5]={1,1,1,1,1};
    while(true)
    {
        //当哲学家饥饿时,总是先拿左边的筷子,再拿右边的筷子
        wait(chopstick[i]);
        wait(chopstick[(i+1)%5]);
        //就餐
        //当哲学家进餐完成后,总是先放下左边的筷子,再放下右边的筷子
        signal(chopstick[i]);
        signal(chopstick[(i+1)%5]);
    }

    为解决死锁的问题,可以使用AND型信号量实现:仅当一个哲学家左右两边的筷子都可用时才允许他进餐。

    semaphore chopstick[5]={1,1,1,1,1};
    do{
        think();        //思考
        Swait(chopstick[(i+1)%5],chopstick[i]);   //请求筷子
        eat();           //就餐
        Ssignal(chopstick[(i+1)%5],chopstick[i]); //释放筷子
    }while(true);

    3. 给出完整代码

    给出完整代码,适当添加注释。注意代码的可读性、可维护性。

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <stdint.h>
      5 #include <stdbool.h>
      6 #include <errno.h>
      7 #include <unistd.h>
      8 #include <sys/types.h>
      9 #include <sys/stat.h>
     10 #include <sys/ipc.h>
     11 #include <sys/sem.h>
     12 #include <sys/wait.h>
     13 union semun{
     14     int val;
     15     struct semid_ds *buf;
     16     unsigned short *array;
     17     struct seminfo *_buf;
     18 };
     19 #define ERR_EXIT(m)
     20 do {
     21     perror(m);
     22     exit(EXIT_FAILURE);
     23 }while(0)
     24 /*相当于p操作,申请一个资源*/
     25 int wait_1chopstick(int no, int semid)
     26 {
     27     struct sembuf sb={ no, -1, 0};
     28     int ret = semop( semid, &sb, 1);
     29     //semop()系统调用在semid标识的信号量集中的信号量上执行一个或多个up或down    操作,可用于进程间的同步和互斥
     30     if(ret<0){
     31         ERR_EXIT("semop");
     32     }
     33     return ret;
     34 }
     35 /*相当于v操作,释放一个资源*/
     36 int free_1chopstick(int no, int semid)
     37 {
     38     struct sembuf sb ={no, 1, 0};
     39     int ret;
     40     ret = semop(semid, &sb, 1);
     41     if(ret<0){
     42         ERR_EXIT("semop");
     43     }
     44     return ret;
     45 }
     46 #define DELAY (rand()%5+1)   //筷子是一个临界资源
     47 /*相当于p操作*/
     48 void wait_for_2chopstick(int no, int semid)
     49 {
     50     int left = no;
     51     int right = (no+1)%5;
     52
     53     struct sembuf buf[2]={
     54         {left, -1, 0},
     55         {right, -1, 0}
     56     };    //左右两边筷子都可用才可进餐
     57     semop(semid, buf, 2);
     58 }
     59 /*相当于v操作*/
     60 void free_2chopstick(int no, int semid)
     61 {
     62     int left = no;
     63     int right = (no+1)%5;
     64         struct sembuf buf[2] = {
     65             {left, 1, 0},
     66             {right, 1, 0}
     67         };
     68         semop(semid, buf, 2);
     69 }
     70 void philosophere(int no, int semid)
     71 {
     72     srand(getpid());
     73     for(;;){
     74         #if 1
     75         printf("哲学家%d 正在思考
    ", no);
     76         sleep(DELAY);
     77         printf("哲学家%d 饿了
    ", no);
     78         wait_for_2chopstick(no, semid);
     79         printf("哲学家%d 正在进餐
    ", no);
     80         sleep(DELAY);
     81         free_2chopstick(no, semid);
     82         #else
     83         //可能会造成死锁
     84         int left = no;
     85         int right = (no+1)%5;
     86         printf("哲学家%d 正在思考
    ", no);
     87         sleep(DELAY);
     88         printf("哲学家%d 饿了
    ", no);
     89         wait_1chopstick(left, semid);
     90         sleep(DELAY);
     91         wait_1chopstick(right,semid);
     92         printf("哲学家%d 正在进餐
    ", no);
     93         sleep(DELAY);
     94         free_1chopstick(left, semid);
     95         free_1chopstick(right, semid);
     96         #endif
     97     }
     98 }
     99 int main(int argc, char*argv[]){
    100     int semid;  //创建信号量
    101     semid = semget(IPC_PRIVATE, 5 , IPC_CREAT | 0666);
    102     if(semid<0){
    103        ERR_EXIT("semid");
    104     }
    105     union semun su;
    106     su.val = 1;
    107     int i;
    108     for(i = 0; i<5; i++){
    109         semctl(semid, i, SETVAL,su);
    110     }
    111     //创建4个子进程
    112     int num=0;
    113     pid_t pid;
    114     for(i=0; i<5; i++){
    115         pid=fork();
    116         if(pid<0){
    117             ERR_EXIT("fork");
    118         }
    119         if(0 == pid){
    120             num= i;
    121             break;
    122         }
    123     }
    124     philosophere(num, semid); //num代表进程号
    125     return 0;
    126 }

    4. 运行结果并解释

    给出运行结果截图,并解释结果。

     解释:

    一开始五个哲学家都在思考,

    然后第一个哲学家(编号为0)饿了,此时两边的筷子都可用所以哲学家0可以进餐

    第五个哲学家(编号为4)饿了,但此时他右边的筷子被哲学家0占用了,不能进餐

    第四个哲学家(编号为3)饿了,此时两边的筷子都可用所以哲学家3可以进餐

    第三个哲学家(编号为2)饿了,但此时他右边的筷子被哲学家3占用了,不能进餐

    然后第四个哲学家(编号为3)进餐完毕,正在思考,此时哲学家2可以进餐

  • 相关阅读:
    A. Ivan the Fool and the Probability Theory
    关于消除“输出中最后的一个空格”问题
    半文件式输入中一种常见的输入方式
    持续输入问题
    汉诺塔问题
    给定两个正整数,求它们的最大公约数。
    第三届全国高校绿色计算机大赛(初赛题目)
    第三届全国高校绿色计算机大赛(初赛题目)
    C++中的输入及其原理简析
    流感传染
  • 原文地址:https://www.cnblogs.com/lvyuhua/p/12997324.html
Copyright © 2011-2022 走看看