Linux下信号量实现进程同步、互斥(生产者消费者问题)

来源:互联网 发布:语音随机聊天软件 编辑:程序博客网 时间:2024/05/23 20:42

操作系统分析的一个小实验

运用Linux平台下的进程间同步和互斥机制,设计实现一个生产者进程和一个消费者进程通过共享内存交换数据,并能达到以下要求:一个仓库可以存放K件物品。生产者每生产一件产品,将产品放入仓库,仓库满了就停止生产。消费者每次从仓库中去一件物品,然后进行消费,仓库空时就停止消费。

因为有生产者、消费者以及仓库,所以需要三个信号量:full、empty和mutex分别表示仓库的库存的同步信号量、仓库为空的同步信号量和正在对仓库进行操作的互斥信号量。其初值分别为0、仓库的容量(程序中使用MAX_BUFFRT_SIZE表示)和0。流程图如图所示。

生产者:

p(empty) -> p(mutex) -> v(mutex) -> v(full)

消费者:

p(full) -> p(mutex) -> v(mutex) ->v(empty)

环境如下:Ubuntu14.04.3,gcc(4.8.2),codeblocks(13.12)

//copyright @Vista(njupt)
#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <sys/shm.h>#include <sys/stat.h>#include <stdio.h>#include <unistd.h>/*KEY 为申请信号量的键值,通过键值可以用于不同进程间的通信*/#define KEY (key_t)14010322/*仓库大小*/#define MAX_BUFFER_SIZE10/*union semun 常用于semctl的最后一个参数, 有的系统上sem.h已包含,可能会因为重复而报错, 如果报错请将其去除。*/union semun {    int val;    struct semid_ds *buf;    ushort *array;};/*仓库,buffer数组用于存贮生产的商品编号(product) write用于记录生产者生产的下一个商品应存贮在仓库的位置 read用于记录消费者消费的下一个商品在仓库中的位置 很明显这是个循环队列,write、read分别为头尾指针*/typedef struct _tagShareBuffer{    int buffer[MAX_BUFFER_SIZE];    int writer;    int reader;}SHAREBUFFER;static void p(int semid ,int semNum);static void v(int semid ,int semNum);int main(){    int  shmid;                        //共享内存的id    char* shmPtr;    intsemid;                          //信号量指针    int product = 1;                    //产品编号,从1开始    SHAREBUFFER* pSharebuffer;          //共享内存的指针    int i;        /*申请信号量*/    if ((semid = semget(KEY,3,IPC_CREAT|0660)) == -1)    {        printf("semget error! \n");        return -1;    }        /*三个信号量的初始赋值*/    union semun arg[3];    arg[0].val = 1;                     //mutex(0)    arg[1].val = MAX_BUFFER_SIZE;       //empty(1)    arg[2].val = 0;                     //full(2)        for(i=0;i<3;i++)        semctl(semid,i,SETVAL,arg[i]);        /*显示三个信号量的初值*/    for(i=0;i<3;i++)        printf("The semval(%d) = %d\n",i,semctl(semid,i,GETVAL,NULL));        /*申请共享内存*/    if ((shmid = shmget(IPC_PRIVATE,sizeof(SHAREBUFFER),0600)) < 0)    {        printf("shmget error!\n");        return -1;    }            if((shmPtr = (char*)shmat(shmid,0,0)) == (void*)-1)    {        printf("shmat error!\n");        return -1;    }        memset((void*)shmPtr,0,sizeof(SHAREBUFFER));        pSharebuffer = (SHAREBUFFER*)shmPtr;        /*创建进程*/    pid_t pid = fork();    if (pid < 0){        printf("creat process error.\n");        return -1;    }    if (pid == 0){        /*子进程,消费者*/        while(1)        {                        p(semid ,2);//P(full)            p(semid ,0);//P(mutex)                        /*输出三个信号量的值和消费仓库中的产品编号以及位置*/            product = pSharebuffer->buffer[pSharebuffer->reader];            for(i=0;i<3;i++)                printf("son:The semval(%d) = %d\n",i,semctl(semid,i,GETVAL,NULL));            printf("son:release the product from buffer[%d] = %d;\n",pSharebuffer->reader,product);                        /* reader++ */            pSharebuffer->reader = (pSharebuffer->reader + 1) % MAX_BUFFER_SIZE;                        v(semid ,0);//V(mutex)            v(semid ,1);    //V(empty)                        sleep(1);       //调节消费速度        }    }    else {        //父进程,生产者        while(1)        {            p(semid ,1);//P(empty)            p(semid ,0);//P(mutex)                        /*输出三个信号量的值和生产仓库中的产品编号以及位置*/            pSharebuffer->buffer[pSharebuffer->writer] = product;            for(i=0;i<3;i++)                printf("parents:The semval(%d) = %d\n",i,semctl(semid,i,GETVAL,NULL));            printf("parents:Produced the product into buffer[%d] = %d;\n",pSharebuffer->writer,product);            /* 产品编号++ */            product++;            /* write++ */            pSharebuffer->writer = (pSharebuffer->writer + 1) % MAX_BUFFER_SIZE;                        v(semid ,0);//V(mutex)            v(semid, 2);    //V(full)                        sleep(1);       //调节生产速度        }    }    return 0;}/* p操作 */void p(int semid ,int semNum){    struct sembuf sb;    sb.sem_num = semNum;    sb.sem_op = -1;    sb.sem_flg = SEM_UNDO;    semop(semid, &sb, 1);}/* v操作 */void v(int semid ,int semNum){    struct sembuf sb;    sb.sem_num = semNum;    sb.sem_op = 1;    sb.sem_flg = SEM_UNDO;    semop(semid, &sb, 1);}


实验的结果如下。值得注意的是,如果输出的结果总是差不多的,那么可能要调节一下生产或者是消费的速度,用sleep就好了。有意义进程的并发性,结果几乎是随机的。

参考文献:

http://blog.csdn.net/yaozhiyi/article/details/7561759

《Linux程序设计(第四版)》

最后说一下,《Linux程序设计》这本书写的真不错,很值得学习。
博主还是菜鸟,有不对或需要改进的地方还请大牛们多多指教。


0 0
原创粉丝点击