system v共享内存与信号量综合

ipc.h

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

#ifndef _IPC_H_
#define _IPC_H_

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    
    struct seminfo *_buf;
};

int sem_create(key_t key);
int sem_open(key_t key);

int sem_p(int semid);
int sem_v(int semid);
int sem_d(int semid);
int sem_setval(int semid, int val);
int sem_getval(int semid);
int sem_getmode(int semid);
int sem_setmode(int semid, char* mode);

#endif //_IPC_H_

ipc.c

#include "ipc.h"

int sem_create(key_t key)
{
    int semid = semget(key,1,0666 | IPC_CREAT | IPC_EXCL);
    if (-1 == semid)
    {
        printf("sem create faild
");
        exit(1);
    }
    return semid;
}
int sem_open(key_t key)
{
    int semid = semget(key,0,0);
    if (-1 == semid)
    {
        printf("sem open faild
");
        exit(1);
    }
    return semid;
}

int sem_p(int semid)
{
    struct sembuf sb = {0,-1,0};
    int ret = semop(semid,&sb,1);
    if(-1 == ret)
    {    
        printf("sem p faild
");
        exit(1);
    }
    return ret;
}
int sem_v(int semid)
{
    struct sembuf sb = {0,1,0};
        int ret = semop(semid,&sb,1);
        if(-1 == ret)
        {
                printf("sem v faild
");
                exit(1);
        }
        return ret;
}
int sem_d(int semid)
{
    int ret = semctl(semid, 0, IPC_RMID, 0);
    return ret;
}
int sem_setval(int semid, int val)
{
    union semun su;
    su.val = val;
    int ret = semctl(semid, 0, SETVAL,su);
    if (-1 == ret)
    {
        printf("sem setval faild
");
        exit(1);
    }
    return ret;
}
int sem_getval(int semid)
{
    int ret = semctl(semid, 0, GETVAL,0);   
        if (-1 == ret)
        {
                printf("sem getval faild
");
                exit(1);
        }
        return ret;
}
int sem_getmode(int semid)
{
    union semun su;
    struct semid_ds sem;
    su.buf = &sem;
    int ret = semctl(semid , 0 , IPC_STAT, su);
    if (-1 == ret)
    {
        printf("sem getmode failed
");
        exit(1);
    }
    printf("current permissions is %o
",su.buf->sem_perm.mode);
    return ret;
}
int sem_setmode(int semid, char* mode)
{
    union semun su;
        struct semid_ds sem;
        su.buf = &sem;
        int ret = semctl(semid , 0 , IPC_STAT, su);
        if (-1 == ret)
        {
                printf("sem getmode failed
");
                exit(1);
        }
        printf("current permissions is %o
",su.buf->sem_perm.mode);
    sscanf(mode ,"%o",(unsigned int*)&su.buf->sem_perm.mode);
    ret = semctl(semid , 0 , IPC_STAT, su);
        if (-1 == ret)
        {
                printf("sem getmode failed
");
                exit(1);
        }
    printf("permissios update...
");
    
    return ret;
}

shmfifo.h

#include "ipc.h"

#ifndef _SHM_FIFO_H_
#define _SHM_FIFO_H_


typedef struct shmfifo shmfifo_t;
typedef struct shmhead shmhead_t;

typedef struct stu
{
        char name[32];
        int age;
}STU;

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;                    // 共享内存ID
    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_destroy(shmfifo_t *fifo);//释放共享内存的环形缓冲区

#endif /* _SHM_FIFO_H_ */

shmfifo.c

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

shmfifo_t* shmfifo_init(int key, int blksize, int blocks)
{
    //分配内存空间
    shmfifo_t *fifo = (shmfifo_t *)malloc(sizeof(shmfifo_t));
    assert(fifo != NULL);
    memset(fifo, 0, sizeof(shmfifo_t));

    int shmid;
    shmid = shmget(key, 0, 0);
    int size = sizeof(shmhead_t) + blksize*blocks;
    if (shmid == -1)
    {//创建共享内存
        fifo->shmid = shmget(key, size, IPC_CREAT | 0666);
        if (fifo->shmid == -1)
            exit(1);

        fifo->p_shm = (shmhead_t*)shmat(fifo->shmid, NULL, 0);
        if (fifo->p_shm == (shmhead_t*)-1)
            exit(1);

        fifo->p_payload = (char*)(fifo->p_shm + 1);

    //进行字段初始化
    fifo->p_shm->blksize = blksize;
    fifo->p_shm->blocks = blocks;
    fifo->p_shm->rd_index = 0;
    fifo->p_shm->wr_index = 0;

        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);
    }
    else
    {//打开共享内存
        fifo->shmid = shmid;
        fifo->p_shm = (shmhead_t*)shmat(fifo->shmid, NULL, 0);
        if (fifo->p_shm == (shmhead_t*)-1)
            exit(1);

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

    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_destroy(shmfifo_t *fifo)
{
    //删除创建的信息量集
    sem_d(fifo->sem_mutex);
    sem_d(fifo->sem_full);
    sem_d(fifo->sem_empty);

    //删除共享内存
    shmdt(fifo->p_shm);//删除共享内存头部
    shmctl(fifo->shmid, IPC_RMID, 0);//删除整个共享内存
    
    //释放fifo的内存 
    free(fifo);
}

shmfifo_send.c

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

shmfifo_recv.c

#include "shmfifo.h"
/*
typedef struct stu
{
        char name[32];
        int age;
}STU;
*/
int main(void)
{
        shmfifo_t *fifo = shmfifo_init(1234,sizeof(STU),3);

        STU s;
        memset(&s, 0, sizeof(STU));
       
        int i;
        for(i=0;i<10;i++)
        {
                shmfifo_get(fifo,&s);
                printf("name = %s, age = %d
",s.name,s.age);
        }
        return 0;
}

shmfifo_free.c

#include "shmfifo.h"

int main(void)
{
    shmfifo_t *fifo = shmfifo_init(1234,sizeof(STU),3);
    shmfifo_destroy(fifo);
    return 0;
}

Makefile

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN= shmfifo_send shmfifo_recv shmfifo_free
OBJS1=shmfifo_send.o shmfifo.o ipc.o
OBJS2=shmfifo_recv.o shmfifo.o ipc.o
OBJS3=shmfifo_free.o shmfifo.o ipc.o
all:$(BIN)
%.o:%.c
    $(CC) $(CFLAGS) -c $< -o $@
shmfifo_send:$(OBJS1)
    $(CC) $(CFLAGS) $^ -o $@
shmfifo_recv:$(OBJS2)
    $(CC) $(CFLAGS) $^ -o $@
shmfifo_free:$(OBJS3)
    $(CC) $(CFLAGS) $^ -o $@

clean:
    rm -f *.o $(BIN)
原文地址:https://www.cnblogs.com/Malphite/p/7786711.html