用信号量为共享内存添加同步机制(3)

#include "shmfifo.h"
 
typedef union semun{
    int val;
}semun;
 
// 初始化
shmfifo_t* shmfifo_init(key_t key, int blocks, int blksz)
{
    shmfifo_t *p = malloc(sizeof(shmfifo_t));
 
    int shmid = shmget(key, 0, 0);
    int len = sizeof(shmhead_t) + blocks*blksz; //共享内存段大小
 
    if(shmid == -1 )  // 内存段不存在,创建
    { 
        shmid = shmget(key, len, IPC_CREAT|0644);
        if ( shmid == -1) perror("shmget"),exit(1);
 
        //初始化内存段头
        p->p_head = 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_mutex = semget(key,  1, IPC_CREAT|0644);
        p->sem_empty = semget(key+1, 1, IPC_CREAT|0644);
        p->sem_full  = semget(key+2, 1, IPC_CREAT|0644);
 
        semun su = {1}; //设置互斥信号量初值为1
        semctl(p->sem_mutex, 0, SETVAL, su);
 
        su.val = blocks;
        semctl(p->sem_empty, 0, SETVAL, su);
 
        su.val = 0; //初始不能消费
        semctl(p->sem_full, 0, SETVAL, su);
    }
    else  //内存段存在 ,打开
    {
        p->p_head = shmat(shmid, NULL, 0);
        p->p_payload = (char*)(p->p_head+1);
        p->shmid = shmid;
        p->sem_mutex = semget(key,  0, 0); //
        p->sem_empty = semget(key+1, 0, 0);
        p->sem_full  = semget(key+2, 0, 0);
    }
    return p;
}
 
static void P(int id)
{
    struct sembuf sb[1] = {0,-1, 0};
    semop(id, sb, 1);
}
 
static void V(int id)
{
    struct sembuf sb[1] = {0, 1, 0};
    semop(id, sb, 1);
}
 
// 放入数据
void shmfifo_put(shmfifo_t *fifo, const void *buf)
{
    P(fifo->sem_empty);  //有多少地方可供生产,确保有空位生产
    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;  //取模,保证数据存满时,转从payload处写数据
 
    V(fifo->sem_full);
    V(fifo->sem_mutex);
}
 
// 取得数据
void shmfifo_get(shmfifo_t* pFifo, void *buf)
{
    P(pFifo->sem_full);  //确保有数据可取
    P(pFifo->sem_mutex);
    //从内存段读取,拷入buf中 
    memcpy(buf,
            pFifo->p_payload + pFifo->p_head->rd_idx* pFifo->p_head->blksz,
            pFifo->p_head->blksz); 
 
    pFifo->p_head->rd_idx = (pFifo->p_head->rd_idx+1)
        %pFifo->p_head->blocks;  //取模,保证数据存满时,转从payload处取数据
 
    V(pFifo->sem_empty);
    V(pFifo->sem_mutex);
}
 
// 销毁
void shmfifo_destroy(shmfifo_t* pFifo)
{
    shmdt(pFifo->p_head);  //取消内存段挂载
    shmctl(pFifo->shmid, IPC_RMID, 0); //释放掉该内存段
    //删除信号量
    semctl(pFifo->sem_mutex, 0, IPC_RMID, 0);
    semctl(pFifo->sem_empty, 0, IPC_RMID, 0);
    semctl(pFifo->sem_full, 0, IPC_RMID, 0);
 
    free(pFifo);
}                                                                                                         

最后就是分别实现get.c和put.c进行验证,

get.c

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/90042d57dd40cc272c9826cdc5d6cf2f.html