实现哲学家问题和生产者消费者模型

利用信号量实现互斥访问资源:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>

//本例描述互斥的打印字符AAZZ必须成对出现

union  semun{
    int val;
};

int id;

void print(char c)
{
    int i = 5;

    struct sembuf sb[1];
    sb[0].sem_num = 0;
    sb[0].sem_flg = 0;
    while(i--)
    {
        sb[0].sem_op = -1;  //P操作
        semop(id, sb, 1);

        printf("%c", c);    //这里可以看做打印两个字符的操作是
        fflush(stdout);     //绑定在一起的,无论间隔多长时间
        sleep(rand()%3);
        printf("%c", c);
        fflush(stdout);

        sb[0].sem_op = 1;   //V操作
        semop(id, sb, 1);
        sleep(rand()%2);
    }
}

int main()
{
    srand(getpid());
    id = semget(123, 1, IPC_CREAT|0644);
    if(-1 == id)  perror("semget"), exit(1);

    union semun su = {1};
    if(-1 == semctl(id, 0, SETVAL, su))
    {
        perror("semctl");
        exit(1);
    }
    pid_t pid =  fork();
    if(-1 == pid)
    {
        perror("fork");
        exit(1);
    }
    else if(0 == pid)
    {
        print('A');
    }
    else 
    {
        print('Z');
    }

    semctl(id, IPC_RMID, 0);
    return 0;
}

信号量互斥和同步实现哲学家思考问题案例:


#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>

//哲学家就餐问题 典型的死锁问题,本程序采用的方法是,
//一个哲学家要么两个筷子都拿到,要么两只筷子都拿不到。

int id;
union semun{
    int value;
};

void GetTwoChop(int no)
{
    struct sembuf sb[2] = {
        {no, -1, 0},
        {(no+1) % 5 , -1,  0}
    };
    semop(id, sb, 2);
}


void PutTwoChop(int no)
{
    struct sembuf sb[2] = {
        {no, 1, 0},
        {(no+1) % 5 , 1, 0}
    };
    semop(id, sb, 2);
}

void fun(int no)
{
    while(1)
    {
        printf("第%d个哲学家开始思考!\n", no);
        sleep(rand()%2);
        GetTwoChop(no);
        printf("第%d个哲学家开始就餐!\n", no);
        sleep(rand()%5);
        printf("第%d个哲学家就餐结束!\n", no);
        PutTwoChop(no);
    }
}

int main()
{
    srand(getpid());    //生成随机数种子

    id = semget(123, 5, IPC_CREAT|0644);  //有5个哲学家,即需要5个信号量
    if(-1 == id)
    {
        perror("semget");
        exit(1);
    }
    union semun su = {1};

    int i = 0;
    int nu = 0;
    for(i = 0; i < 5; i++)
    {
        if (-1 == semctl(id, i, SETVAL, su))//初始化信号量;每根筷子有两种状态
        //  0 和 1
        {
            perror("semctl");
            exit(1);
        }
    }
    for(i = 1 ; i < 5; i++ )       //创建5个进程,一个父进程,4个子进程
    {
        if(0 == fork())
        {
            nu = i;
            break;
        }
    }
    fun(nu);      //每个哲学家有不同的nu,执行不同的操作

    return 0;
}

利用共享内存及信号量知识实现生产者消费者模型:


自定义头文件:

#ifndef __SHMFIFO_H__
#define __SHMFIFO_H__

typedef struct shm_head{
    int rd_idx;     //读出时的位置
    int wr_idx;     //写入时的位置
    int blocks;     //块的数量
    int blksz;      //块的大小
}head_t;

typedef struct shmfifo{
    head_t* p_head;     //共享内存段的头的起始位置
    char* p_payload;    //有效数据的地址
    int shmid;          //共享内存id
    int sem_full;       //共享内存满
    int sem_empty;      //表示还有几个空闲
    int sem_mutex;      //互斥量
}shmfifo_t;

//共享内存段的初始化,需要的参数分别是共享内存段的打开时的
//起始key值, 块的数量, 每块的大小
shmfifo_t* shmfifo_init(int key, int blocks, int blksz);
//生产者生产,即存放操作,需要的参数是共享队列的地址,
//以及要存放的数据的地址,这里不考虑大小是因为我们默认的
//要存入的数据大小和块的大小是相等的
void shmfifo_put(shmfifo_t* fifo, const void* buf);

//消费者消费, 即取出操作,原理同存入操作相同
void shmfifo_get(shmfifo_t* fifo, void* buf);

//共享队列的销毁
void shmfifo_destroy(shmfifo_t* fifo);

#endif  // __SHMFIFO_H__

具体实现:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <assert.h>
#include <string.h>

#include "shmfifo.h"

union semun{
    int value;
};

static void p(int id)
{
    struct sembuf sb[1];
    sb[0].sem_num = 0;
    sb[0].sem_op = -1;
    sb[0].sem_flg = 0;
    semop(id, sb, 1);
}

static void v(int id)
{
    struct sembuf sb[1];
    sb[0].sem_num = 0;
    sb[0].sem_op = 1;
    sb[0].sem_flg = 0;
    semop(id, sb, 1);
}

shmfifo_t* shmfifo_init(int key, int blocks, int blksz)
{
    shmfifo_t* p = (shmfifo_t*)malloc(sizeof(shmfifo_t));
    if(NULL == p)
    {
        perror("malloc");
        exit(1);
    }
    int len = blocks *blksz + sizeof(head_t);
    int shmid = shmget(key, len, 0);
    if(-1 == shmid){    //共享内存段不存在,创建
        shmid = shmget(key, len, IPC_CREAT|0644);
        p->p_head = (head_t*)shmat(shmid, NULL, 0);
        p->p_head->rd_idx = 0;
        p->p_head->wr_idx = 0;
        p->p_head->blocks = blocks;
        p->p_head->blksz = blksz;
        p->p_payload = (char*)(p->p_head + 1);
        p->shmid = shmid;
        p->sem_full = semget(key, 1,  IPC_CREAT|0644);
        p->sem_empty = semget(key + 1, 1, IPC_CREAT|0644);
        p->sem_mutex = semget(key + 2, 1, IPC_CREAT|0644);
        union semun su;
        su.value = blocks;
        semctl(p->sem_full, 0, SETVAL, su);
        su.value = 0;
        semctl(p->sem_empty, 0, SETVAL, su);
        su.value = 1;
        semctl(p->sem_mutex, 0, SETVAL, su);
    }
    else //已经存在,直接打开
    {
        p->p_head = (head_t*)shmat(shmid, NULL, 0);
        p->p_payload = (char*)(p->p_head + 1);
        p->shmid = shmid;
        p->sem_full = semget(key, 0, 0);
        p->sem_empty = semget(key + 1, 0, 0);
        p->sem_mutex = semget(key + 2, 0, 0);
    }
    return p;
}

void shmfifo_put(shmfifo_t *fifo, const void* buf)
{
    p(fifo->sem_full);  //同步,共享队列中生产者生产,类似于判断共享队列是否满
    p(fifo->sem_mutex); //互斥访问当前正在写入的资源

    memcpy(fifo->p_payload + (fifo->p_head->wr_idx * fifo->p_head->blksz),
           buf, fifo->p_head->blksz);
    fifo->p_head->wr_idx = (fifo->p_head->wr_idx + 1) % fifo->p_head->blocks;

    v(fifo->sem_mutex);
    v(fifo->sem_empty);
}

void shmfifo_get(shmfifo_t *fifo, void* buf)
{
    p(fifo->sem_empty);  //同步
    p(fifo->sem_mutex); //互斥

    memcpy(buf, fifo->p_payload + (fifo->p_head->rd_idx * fifo->p_head->blksz),
            fifo->p_head->blksz);
    fifo->p_head->rd_idx = (fifo->p_head->rd_idx + 1) % fifo->p_head->blocks;

    v(fifo->sem_mutex);
    v(fifo->sem_full);
}

void shmfifo_destroy(shmfifo_t* fifo)
{
    shmdt(fifo->p_head);
    shmctl(fifo->shmid, IPC_RMID, 0);
    shmctl(fifo->sem_full, 0, IPC_RMID);
    shmctl(fifo->sem_empty, 0, IPC_RMID);
    shmctl(fifo->sem_mutex, 0, IPC_RMID);

    free(fifo);
    fifo = NULL;
}

存放操作:

#include <stdio.h>
#include "shmfifo.h"

typedef struct person{
    char _name[32];
    int _age;
}person_t;

int main()
{
    shmfifo_t* fifo = shmfifo_init(123, 5, sizeof(person_t));
    person_t person;
    
    int i = 0;
    for(; i < 10; i++)
    {
        person._age = 10 + i;
        sprintf(person._name, "name:%d", i+1);
        shmfifo_put(fifo,&person);
        printf("put %d\n", i+1);
    }
    return 0;
}
取出操作:
#include <stdio.h>
#include "shmfifo.h"

typedef struct person{
    char _name[32];
    int _age;
}person_t;

int main()
{
    shmfifo_t* fifo = shmfifo_init(123, 5, sizeof(person_t));
    person_t person;
    
    int i = 0;
    for(; i < 10; i++)
    {
        shmfifo_get(fifo, &person);
        printf("name = %s, age = %d \n", person._name, person._age);
        sleep(1);
    }

    shmfifo_destroy(fifo);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/bian_cheng_ru_men/article/details/80161225