首页 > 代码库 > Linux 信号量 生产者消费者小例题 (嘘,我是菜鸟~)

Linux 信号量 生产者消费者小例题 (嘘,我是菜鸟~)

<style></style>

  菜鸟偶遇信号量,擦出火花(只有不熟才会有火花)。于是上网搜资料和看《Unix环境高级编程》实现了几个小例题,高手请勿喷!这几位写得非常好啊:

题目来源: http://www.it165.net/os/html/201312/7039.html

信号量及其用法:http://www.cnblogs.com/hjslovewcl/archive/2011/03/03/2314341.html

Mutex与Semaphore区别著名的厕所理论:http://koti.mbnet.fi/niclasw/MutexSemaphore.html

   哎呀,暴露了!我不是故意偷窥别人的……




 

一:一个生产者、一个消费者、一个资源情况

  这种情况情况可以只用一个信号量,要生成或要消费只用尝试获取这个信号量,这里用了两个:full=1和empty=0,两个只为了和后面一致,1、0是赋初值。生产者和消费者情况如下:

//生产者:P(empty)    生成资源并放进资源处V(full)//消费者:P(full)    消费资源V(empty)

  若生产者最先开始生产资源,P(empty),full和empty都成了0,此时若消费者想要消费,则P(full)时,full为0则睡眠等待,等生产者生结束就把full加1,看到消费者可怜地睡着了就唤醒它,然后消费者把full减1自己快活去了。

  消费者消费过程中生产者若要生了,则会因为empty为0而休眠,等消费者结束就把empty加1,然后生产者开始生产。

  上面的好理解,下面上代码:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#include <x86_64-linux-gnu/sys/types.h>#include <x86_64-linux-gnu/sys/ipc.h>#include <x86_64-linux-gnu/sys/sem.h>int semInite(int semId, int value);int semDelete(int semId);int semP(int semId);int semV(int semId);//declare a union to be usedunion semun {    int val;                        /* value for SETVAL */     struct semid_ds *buf;                /* buffer for IPC_STAT, IPC_SET */     unsigned short int *array;         /* array for GETALL, SETALL */     struct seminfo *__buf;                /* buffer for IPC_INFO */ };//semaphore declarestatic int semFullId;static int semEmptyId;static int source = 0;        //source definition    //new thread as a consumervoid* child_thread(void* arg){    int ttt = 1;            while(1)    {        sleep(rand() % 19);        printf("child No.%d times wants to consume...\n", ttt);                semP(semFullId);    //        printf("child No.%d times start consuming. source = %d\n", ttt, source);        source = 0;        printf("child No.%d times end consuming. source = %d\n\n", ttt++, source);        semV(semEmptyId);    //    }        return (void*)0;}int main(void){        //create semaphore    semFullId = semget((key_t)1235, 1, 0666 | IPC_CREAT);    semEmptyId = semget((key_t)1236, 1, 0666 | IPC_CREAT);    semInite(semFullId, 0);    semInite(semEmptyId, 1);        pthread_t pid;    pthread_create(&pid, NULL, child_thread, NULL);        int tt = 1;        while(1)    {        sleep(rand() % 18);        printf("parent No.%d times wants to produce...\n", tt);                semP(semEmptyId);    //        printf("parent No.%d times start producing. source = %d\n", tt, source);        source = rand() % 100;        printf("parent No.%d times end producing. source = %d\n", tt++, source);        semV(semFullId);    //    }        semDelete(semFullId);    semDelete(semEmptyId);    return 0;}//set semaphore as default valueint semInite(int semId, int value){    union semun semUnion;    semUnion.val = value;    //set default semaphore    return semctl(semId, 0, SETVAL, semUnion);}//delete semaphoreint semDelete(int semId){    union semun semUnion;    return semctl(semId, 0, IPC_RMID, semUnion);}//semaphore P operationint semP(int semId){    struct sembuf semBuf;    semBuf.sem_num = 0;        //indicate it is not semaphore array    semBuf.sem_op = -1;        //subtract one    semBuf.sem_flg = SEM_UNDO;        return semop(semId, &semBuf, 1);    //return value}//semaphore V operationint semV(int semId){    struct sembuf semBuf;    semBuf.sem_num = 0;        //indicate it is not semaphore array    semBuf.sem_op = 1;        //subtract one    semBuf.sem_flg = SEM_UNDO;        return semop(semId, &semBuf, 1);    //return value}
111

两个线程,创建的新线程当做消费者了。其中unix的几个信号量的函数看了半天,有点复杂,简单不准确来讲:

//获得一个信号量啦,第二个参数是想要创建的信号量个数,//因为unix操作的是信号量集合,设为1不就一个信号量了嘛//其他参数我不管了int semget(key_t key, int num_sems, int sem_flags);//信号量集合的操作,这个可以用来实现P、V的 +1 -1 的功能int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);//信号量集合的控制,如初始化删除等int semctl(int sem_id, int sem_num, int command, ...);

运行: