Linux下的简单生产、消费模型的实现(下)

来源:互联网 发布:mac twisted 安装 编辑:程序博客网 时间:2024/05/20 02:21
生产消费模型中生产者与消费者是互相独立进程,而各个进程的内存空间是相互独立的,因为我们需要为生产者与消费者建立一块共享内存区,用于保存生产出的“产品”。
本文使用循环队列保存“产品”,队列为空时有head=tail=0
struct sharebuf
{
    int buffer[MAX_BUFFER_SIZE];
    int head;
    int tail;
};

共享内存的命名与信号量的命名相同,我们一般使用宏定义
#define KEY_MEM ((key_t)103040914)
Linux提供的库函数为

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_tsize, int shmflg);

此函数将建立一块大小为size字节的共享内存。
需要注意的是,shmget建立的一块共享内存必须使用shmat()才能得到这块内存的地址,库函数如下:

void *shmat(int shmid, const void*shmaddr, int shmflg);

其中shmaddr,shmflg参数使用0即可。返回值得到的地址,就可以像普通指针一样操作了。还需要注意的是这个指针应该进行相应的强制类型转换。
一段建立并初始化共享内存的代码如下:

struct sharebuf * ptr;
int id = shmget(KEY_MEM, sizeof(struct sharebuf), IPC_CREAT);
buf.head = buf.tail = 0;
ptr = (struct sharebuf *)shmat(id, 0, 0);
ptr->tail = ptr->head = 0;


综合上文信号量和共享内存的操作方法,我们将所有相关的操作编写成share.h和share.c


//share.h
#define KEY_MEM ((key_t)103040914)
#define KEY_FULL ((key_t)203040914)
#define KEY_EMPTY ((key_t)303040914)
#define KEY_MUTEX ((key_t)403040914)

#define MAX_BUFFER_SIZE 10

struct sharebuf
{
    int buffer[MAX_BUFFER_SIZE];
    int head;
    int tail;
};

union semun
{
    int val;                  /* value for SETVAL */
        struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
        unsigned short *array;    /* array for GETALL, SETALL */
                                  /* Linux specific part: */
        struct seminfo *__buf;    /* buffer for IPC_INFO */
};

int create(int * id_mem, int * id_full, int * id_empty, int * id_mutex);
void init(int id_mem, int id_full, int id_empty, int id_mutex);
void wait(int id);
void release(int id);
void * getmem(int id);


//share.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include "share.h"

int create(int * id_mem, int * id_full, int * id_empty, int * id_mutex)
{
    *id_mem = shmget(KEY_MEM, sizeof(struct sharebuf), IPC_CREAT);
    *id_full = semget(KEY_FULL, 1, IPC_CREAT|0660);
    *id_empty = semget(KEY_EMPTY, 1, IPC_CREAT|0660);
    *id_mutex = semget(KEY_MUTEX, 1, IPC_CREAT|0660);
    return (*id_mem != -1 && *id_full != -1 &&
        *id_empty != -1 && *id_mutex != -1);
}

void init(int id_mem, int id_full, int id_empty, int id_mutex)
{
    union semun un;
    struct sharebuf * ptr;
    un.val = MAX_BUFFER_SIZE;
    semctl(id_empty, 0, SETVAL, un);
    un.val = 0;
    semctl(id_full, 0, SETVAL, un);
    un.val = 1;
    semctl(id_mutex, 0, SETVAL, un);
    ptr = getmem(id);
    ptr->tail = ptr->head = 0;
}

void wait(int id)
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = -1;
    buf.sem_flg = SEM_UNDO;
    semop(id, &buf, 1);
}

void release(int id)
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;
    buf.sem_flg = SEM_UNDO;
    semop(id, &buf, 1);
}

void * getmem(int id)
{
    return shmat(id_mem, 0, 0);
}


生产者的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include "share.h"

int main(int argc, char ** args)
{
    int count = 0;
    int id_mem, id_full, id_empty, id_mutex;    
    struct sharebuf * ptr;

    create(&id_mem, &id_full, &id_empty, &id_mutex);
    init(id_mem, id_full, id_empty, id_mutex);
    ptr = (struct sharebuf *)getmem(id_mem);
    
    while (1)
    {
        wait(id_empty);
        wait(id_mutex);
        ptr->buffer[ptr->tail] = count++;
        ptr->tail = (ptr->tail+1)%MAX_BUFFER_SIZE;
        printf("producer:%d/n", count);
        release(id_mutex);
        release(id_full);
    }
    return 0;
}


消费者代码如下:
#include <stdio.h>
#include <stdlib.h>
#include "share.h"

int main(int argc, char ** args)
{
    int n = 0;
    int id_mem, id_full, id_empty, id_mutex;    
    struct sharebuf * ptr;

    create(&id_mem, &id_full, &id_empty, &id_mutex);
    ptr = (struct sharebuf *)getmem(id_mem);
    
    while (1)
    {
        wait(id_full);
        wait(id_mutex);
        n = ptr->buffer[ptr->head];
        ptr->head = (ptr->head+1)%MAX_BUFFER_SIZE;
        printf("customer:%d/n", n);
        release(id_mutex);
        release(id_empty);
    }
    return 0;
}