(P32)system v信號量

1.用信號量集解決哲學家就餐問題

  • 信號量的個數不再是一個
    如果5個哲學家同時處於飢餓的狀態,同時拿起左邊的叉子,想拿起右邊的叉子,但是拿不起來右邊的叉子,會導致死鎖的發生
    避免該死鎖問題:兩個叉子都滿足的情況下,哲學家才能拿起叉子進行用餐,要麼拿到2把叉子,要麼都不拿,這是原子操作

在這裏插入圖片描述

  • eg:NetworkProgramming-master (1)\NetworkProgramming-master\P30sem03.c
//
// Created by wangji on 19-8-13.
//

// p30 system v信號量(二)

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>


#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <wait.h>

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

union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
};

int semid;
//睡眠的時間爲1-5s
#define DELAY (rand() % 5 + 1 )

//模擬死鎖
int wait_1fork(int no)
{
    struct sembuf sb={no, -1 ,0};
    int ret;
    ret=semop(semid, &sb, 1);
    if (ret == -1)
        ERR_EXIT("semop");
    return ret;
}



void get2fork(int pid)
{
    unsigned short int left = pid;//左邊的刀叉編號=哲學家的id編號
    unsigned short int right = (pid + 1) % 5;//右邊的刀叉編號=哲學家id編號+1,以此,得出來的經驗
    struct sembuf sembuf[2] = {{left, -1, 0}, {right, -1, 0}};//刀叉的編號就是信號的序號
    int ret = semop(semid, sembuf, 2);//對信號集中的2個信號量進行操作,要麼同時得到2個叉子,要麼都得不到,就處於等待狀態,等待別的哲學家歸還叉子
    if (ret == -1)
    {
        ERR_EXIT("get2fork")
    }
};

void put2fork(int pid)
{
    unsigned short int left = pid;
    unsigned short int right = (pid + 1) % 5;
    struct sembuf sembuf[2] = {{left, 1, 0}, {right, 1, 0}};
    int ret = semop(semid, sembuf, 2);
    if (ret == -1)
    {
        ERR_EXIT("get2fork")
    }
};


void philosopher(int no)
{
    srand(getpid());//用了rand()隨機數,這裏給隨機數一個種子
    while (1)
    {
        printf("%d is thinking\n", no);//表示哲學家思考
        sleep(DELAY);//哲學家思考一段時間,哲學家餓了
        printf("%d is hungry\n", no);
        get2fork(no);//獲取2個叉子
        printf("%d is eating\n", no);//吃飯
        sleep(DELAY);//吃完飯了
        put2fork(no);//釋放2個叉子




       /*模擬死鎖
        unsigned short int left = pid;
        unsigned short int right = (pid + 1) % 5;
        printf("%d is thinking\n", no);//表示哲學家思考
        sleep(DELAY);//哲學家思考一段時間,哲學家餓了
        printf("%d is hungry\n", no);
        wait_1fork(left); //哲學家看到刀叉就拿起來
        sleep(DELAY);//爲了更快的產生死鎖
        wait_1fork(right); //哲學家看到刀叉就拿起來
        printf("%d is eating\n", no);//吃飯
        sleep(DELAY);//吃完飯了
        put2fork(no);//釋放2個叉子
        */
    }
}


int main(int argc, char** argv)
{
    semid = semget(IPC_PRIVATE, 5, IPC_CREAT | IPC_EXCL | 0666);//創建的信號量集中有5個信號量,模擬5個叉子
    if (semid == -1)
    {
        ERR_EXIT("semid");
    }

    union semun su;
    su.val = 1;
    for (int i = 0; i < 5; ++i)
    {
        semctl(semid, i, SETVAL, su);//初始化爲1表示都是可用的狀態
    }

    int no = 0;
    pid_t pid;
    for (int i = 1; i < 5; ++i)//創建4個子進程
    {
        pid = fork();
        if (pid == -1)
            ERR_EXIT("fork");

        if (pid == 0)
        {
            no = i;
            break;
        }
    }

    philosopher(no);
    return 0;
}
  • 測試結果:
    相鄰的2個哲學家不可能同時處於吃的狀態,也就是不可能出現死鎖的狀態
    在這裏插入圖片描述

  • eg:模擬死鎖NetworkProgramming-master (1)\NetworkProgramming-master\P30sem03.c

//
// Created by wangji on 19-8-13.
//

// p30 system v信號量(二)

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>


#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <wait.h>

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

union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
};

int semid;
//睡眠的時間爲1-5s
#define DELAY (rand() % 5 + 1 )

//模擬死鎖
int wait_1fork(int no)
{
    struct sembuf sb={no, -1 ,0};
    int ret;
    ret=semop(semid, &sb, 1);
    if (ret == -1)
        ERR_EXIT("semop");
    return ret;
}



void get2fork(int pid)
{
    unsigned short int left = pid;//左邊的刀叉編號=哲學家的id編號
    unsigned short int right = (pid + 1) % 5;//右邊的刀叉編號=哲學家id編號+1,以此,得出來的經驗
    struct sembuf sembuf[2] = {{left, -1, 0}, {right, -1, 0}};//刀叉的編號就是信號的序號
    int ret = semop(semid, sembuf, 2);//對信號集中的2個信號量進行操作,要麼同時得到2個叉子,要麼都得不到,就處於等待狀態,等待別的哲學家歸還叉子
    if (ret == -1)
    {
        ERR_EXIT("get2fork")
    }
};

void put2fork(int pid)
{
    unsigned short int left = pid;
    unsigned short int right = (pid + 1) % 5;
    struct sembuf sembuf[2] = {{left, 1, 0}, {right, 1, 0}};
    int ret = semop(semid, sembuf, 2);
    if (ret == -1)
    {
        ERR_EXIT("get2fork")
    }
};


void philosopher(int no)
{
    srand(getpid());//用了rand()隨機數,這裏給隨機數一個種子
    while (1)
    {
    	/*
        printf("%d is thinking\n", no);//表示哲學家思考
        sleep(DELAY);//哲學家思考一段時間,哲學家餓了
        printf("%d is hungry\n", no);
        get2fork(no);//獲取2個叉子
        printf("%d is eating\n", no);//吃飯
        sleep(DELAY);//吃完飯了
        put2fork(no);//釋放2個叉子
		*/

        unsigned short int left = pid;
        unsigned short int right = (pid + 1) % 5;
        printf("%d is thinking\n", no);//表示哲學家思考
        sleep(DELAY);//哲學家思考一段時間,哲學家餓了
        printf("%d is hungry\n", no);
        wait_1fork(left); //哲學家看到刀叉就拿起來
        sleep(DELAY);//爲了更快的產生死鎖
        wait_1fork(right); //哲學家看到刀叉就拿起來
        printf("%d is eating\n", no);//吃飯
        sleep(DELAY);//吃完飯了
        put2fork(no);//釋放2個叉子
        
    }
}


int main(int argc, char** argv)
{
    semid = semget(IPC_PRIVATE, 5, IPC_CREAT | IPC_EXCL | 0666);//創建的信號量集中有5個信號量,模擬5個叉子
    if (semid == -1)
    {
        ERR_EXIT("semid");
    }

    union semun su;
    su.val = 1;
    for (int i = 0; i < 5; ++i)
    {
        semctl(semid, i, SETVAL, su);//初始化爲1表示都是可用的狀態
    }

    int no = 0;
    pid_t pid;
    for (int i = 1; i < 5; ++i)//創建4個子進程
    {
        pid = fork();
        if (pid == -1)
            ERR_EXIT("fork");

        if (pid == 0)
        {
            no = i;
            break;
        }
    }

    philosopher(no);
    return 0;
}
  • 測試結果:
    5個哲學家都處於thinkng狀態,hungry狀態,5個哲學家同時都去拿起左叉子

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章