SYSTEM V 信号量和共享内存(生产者和消费者模式)

信号量:

ipc.h

#ifndef _IPC_H
#define _IPC_H_


#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <error.h>
#include <stdlib.h>


int sem_create(int);
int sem_open(int);

int sem_setval(int, int);

int sem_p(int);
int sem_v(int);

int sem_delete(int);

#endif

ipc.c

#include "ipc.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) */
};


int sem_create(int key)
{
    int semid;
   
    semid = semget(key, 1, IPC_CREAT|0666);
    if(semid == -1)
        exit(EXIT_FAILURE);


    return semid;
}


int sem_open(int key)
{
    int semid;
   
    semid = semget(key, 0, 0);
    if(semid == -1)
        exit(EXIT_FAILURE);


    return semid;
}


int sem_setval(int semid, int val)
{
    int ret;
    union semun sem_arg;
    sem_arg.val = val;
    if((ret = semctl(semid, 0, SETVAL, sem_arg)) == -1)
    {
        exit(EXIT_FAILURE);
    }


    return ret;
}


int sem_p(int semid)
{
    struct sembuf buf;
    int ret;
   
    buf.sem_num = 0;
    buf.sem_op = -1;
    buf.sem_flg = SEM_UNDO;


    if((ret = semop(semid, &buf, 1)) == -1)
    {
        exit(EXIT_FAILURE);
    }


    return ret;
}


int sem_v(int semid)
{
    struct sembuf buf;
    int ret;
   
    buf.sem_num = 0;
    buf.sem_op = 1;
    buf.sem_flg = SEM_UNDO;


    if((ret = semop(semid, &buf, 1)) == -1)
    {
        exit(EXIT_FAILURE);
    }


    return ret;
}


int sem_delete(int semid)
{
    int ret;


    ret = semctl(semid, 1, IPC_RMID, 0);
    if(ret == -1)
    {
        exit(EXIT_FAILURE);
    }


    return ret;
}

共享内存:

shm_fifo.h

#ifndef _SHM_FIFO_H
#define _SHM_FIFO_H_
#include "ipc.h"
#include <sys/shm.h>


typedef struct shmfifo shmfifo_t;
typedef struct shmhead shmhead_t;
struct shmhead
{
    unsigned int blksize;       //块大小
    unsigned int blocks;        //总块数
    unsigned int rd_index;      //读索引
    unsigned int wr_index;      //写索引
};
struct shmfifo
{
    shmhead_t *p_shm;           //共享内存头部指针
    char *p_payload;            //有效负载的起始地址
    int shmid;                  //共享内存IO
    int sem_mutex;              //用来互斥用的信号量
    int sem_full;               //用来控制共享内存是否满的信号量
    int sem_empty;              //用来控制共享内存是否空的信号量
};
shmfifo_t* shmfifo_init(int key,int blksize,int blocks);
void shmfifo_put(shmfifo_t *fifo,const void* buf);
void shmfifo_get(shmfifo_t *fifo,void *buf);
void shmfifo_destory(shmfifo_t *fifo);
#endif/* _SHM_FIFO_H  */

shm_fifo.c

#include "shm_fifo.h"
#include <string.h>




shmfifo_t* shmfifo_init(int key, int blksize, int blocks)
{
    shmfifo_t *fifo = NULL;
    int shmid;
    int size;
   
    fifo = (shmfifo_t *)malloc(sizeof(shmfifo_t));
    if(!fifo)
        return NULL;


    memset(fifo, 0, sizeof(shmfifo_t));


    // 判断共享内存是否存在
    shmid = shmget(key, 0, 0);


    // 需要创建共享内存的大小
    size = sizeof(shmhead_t) + blksize * blocks;


    // 如果不存在
    if(shmid == -1)
    {
        // 创建一个共享内存
        fifo->shmid = shmget(key, size, IPC_CREAT | 0666);
        if(fifo->shmid == -1)
            exit(EXIT_FAILURE);
       
        // 头部指针指向共享内存
        fifo->p_shm = (shmhead_t *)shmat(fifo->shmid, NULL, 0);
        if(fifo->p_shm == (shmhead_t*)-1)
            exit(EXIT_FAILURE);
        fifo->p_payload = (char*)(fifo->p_shm + 1);


        // 设置信号量
        fifo->sem_mutex = sem_create(key);
        fifo->sem_full = sem_create(key+1);
        fifo->sem_empty = sem_create(key+2);


        //信号量初始化
        sem_setval(fifo->sem_mutex, 1);
        sem_setval(fifo->sem_full, blocks);
        sem_setval(fifo->sem_empty, 0);    


        //头部初始化
        fifo->p_shm->blksize = blksize;
        fifo->p_shm->blocks = blocks;
        fifo->p_shm->rd_index  = 0;
        fifo->p_shm->wr_index = 0;    
    }
    // 如果存在
    else
    {
        fifo->shmid = shmid;


        //头部指针指向共享内存
        fifo->p_shm = (shmhead_t*)shmat(fifo->shmid, NULL , 0);
        if( fifo->p_shm == (shmhead_t*)-1 )
            exit(EXIT_FAILURE);
        fifo->p_payload = (char*)(fifo->p_shm + 1);
        fifo->sem_mutex = sem_open(key);
        fifo->sem_full = sem_open(key+1);
        fifo->sem_empty = sem_open(key+2);


        //读写索引初始化
         fifo->p_shm->rd_index  = 0;
         fifo->p_shm->wr_index = 0;
    }


    return fifo;
}




//生产者
void shmfifo_put(shmfifo_t *fifo,const void* buf)
{
    sem_p(fifo->sem_full);
    sem_p(fifo->sem_mutex);
   
    memcpy(fifo->p_payload+fifo->p_shm->blksize*fifo->p_shm->wr_index,  buf, fifo->p_shm->blksize);
    fifo->p_shm->wr_index = (fifo->p_shm->wr_index + 1) % fifo->p_shm->blocks;
    sem_v(fifo->sem_mutex);
    sem_v(fifo->sem_empty);
}


//消费者
void shmfifo_get(shmfifo_t *fifo,void* buf)
{
    sem_p(fifo->sem_empty);
    sem_p(fifo->sem_mutex);
   
    memcpy(buf, fifo->p_payload+fifo->p_shm->blksize*fifo->p_shm->rd_index,  fifo->p_shm->blksize);
    fifo->p_shm->rd_index = (fifo->p_shm->rd_index + 1) % fifo->p_shm->blocks;
    sem_v(fifo->sem_mutex);
    sem_v(fifo->sem_full);
}
void shmfifo_destory(shmfifo_t *fifo)
{
    sem_delete(fifo->sem_mutex);
    sem_delete(fifo->sem_full);
    sem_delete(fifo->sem_empty);
   
    int shmid = fifo->shmid;
    shmctl(fifo->shmid, IPC_RMID, 0);
    free(fifo);
}

示例:

生产者:

#include "shm_fifo.h"
typedef struct stu
{
    char name[32];
    int age;
}STU;
int main(void)
{
    shmfifo_t *fifo = shmfifo_init(1234,sizeof(STU),3);
    int i;
    STU s;
    memset(&s, 0, sizeof(STU));
    s.name[0] = 'A';
    for(i=0; i<5; i++)
    {
        s.age = 20 + i;
        shmfifo_put(fifo,&s);
        s.name[0] = s.name[0] + 1;
        printf("send ok\n");
    }
    return 0;
}

消费者:


#include "shm_fifo.h"
typedef struct stu
{
    char name[32];
    int age;
}STU;
int main(void)
{
    shmfifo_t *fifo = shmfifo_init(1234,sizeof(STU),3);
    int i;
    STU s;
    memset(&s, 0, sizeof(STU));
    for(i=0; i<10; i++)
    {
        shmfifo_get(fifo,&s);
        printf("recv:name = %s,age=%d\n",s.name,s.age);
    }

    shmfifo_destory(fifo);
    return 0;
}

编译:

gcc -c ipc.c -o ipc.o -g
gcc -c shm_fifo.c -o shm_fifo.o -g
gcc -c client.c -o client.o -g
gcc -c server.c -o server.o -g
gcc client.o ipc.o shm_fifo.o -o client -lpthread -lrt -g
gcc server.o ipc.o shm_fifo.o -o server -lpthread -lrt -g

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值