第三十二章 System V信号量(三)

n哲学家进餐问题描述有五个哲学家,他们的生活方式是交替地进行思考和进餐,n哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,n平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,n进餐完毕,放下筷子又继续思考。

约束条件

(1)只有拿到两只筷子时,哲学家才能吃饭。
(2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
(3)任一哲学家在自己未拿到两只筷子吃饭前,不会放下手中拿到的筷子。

问题的产生
如果5个哲学家同时拿起了左边的筷子,
那么5个哲学家同时又会请求右手边的筷子,
由于每个哲学家都只有一个筷子,无法进餐,又连续的请求右手边没有的筷子,就会一直进入等待的状态(死锁)
这样5个哲学家就饿死了

在IPC进程通信中我们了解过,我们可以把五个哲学家想象成五个进程,而那五个筷子就是临界区的临界资源,
只有某个进程得到临界区的两个资源才能进行下去,否则会一直阻塞,那么就可以用一组 5个 信号量表示5个筷子,每个信号量的值为0或1 表示此筷子是否被使用中

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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) */
};

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

int sem_p(int semid)
{
    struct sembuf sops = {0, -1, 0};
    int ret;
    ret = semop(semid, &sops, 1);
    if(ret == -1)
        ERR_EXIT("semop");

    return 0;
}

int sem_v(int semid)
{
    struct sembuf sops = {0, 1, 0};
    int ret;
    ret = semop(semid, &sops, 1);
    if(ret == -1)
        ERR_EXIT("semop");

    return 0;
}

#define DELAY (rand()%5 + 1)
int semid;

void wait_for_2fork(int no)
{
    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 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)
{
    srand(getpid());
    for(;;)
    {
        printf("%d is thinking...\n", no);
        sleep(DELAY);
        printf("%d is hangry\n", no);
        
        wait_for_2fork(no);
        printf("%d is eating\n",no);
        free_2fork(no);
    }
}

int main(int argc, char* argv[])
{

    semid = semget(IPC_PRIVATE, 5, IPC_CREAT|0666);
    if(semid == -1)
        ERR_EXIT("semget");

    
    int  i;
    union semun su;
    su.val = 1;
    for(i=0; i<5; ++i)
    {
        semctl(semid, i, SETVAL, su);
    }

    int no = 0;
    pid_t pid;
    for(i=1; i<5; ++i)
    {
        pid = fork();
        if(pid == -1)
            ERR_EXIT("fork");

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

    philosophere(no);

    return 0;
}
posted @ 2019-09-26 10:13  sfdevs  阅读(104)  评论(0编辑  收藏  举报