Linux 信号量 生产者消费者小例题
菜鸟偶遇信号量,擦出火花(只有不熟才会有火花)。于是上网搜资料和看《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 used union 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 declare static int semFullId; static int semEmptyId; static int source = 0; //source definition //new thread as a consumer void* 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 semaphoresemFullId = 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 value int semInite(int semId, int value) {union semun semUnion;semUnion.val = value; //set default semaphorereturn semctl(semId, 0, SETVAL, semUnion); }//delete semaphore int semDelete(int semId) {union semun semUnion;return semctl(semId, 0, IPC_RMID, semUnion); }//semaphore P operation int semP(int semId) {struct sembuf semBuf;semBuf.sem_num = 0; //indicate it is not semaphore arraysemBuf.sem_op = -1; //subtract onesemBuf.sem_flg = SEM_UNDO;return semop(semId, &semBuf, 1); //return value }//semaphore V operation int semV(int semId) {struct sembuf semBuf;semBuf.sem_num = 0; //indicate it is not semaphore arraysemBuf.sem_op = 1; //subtract onesemBuf.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, ...);
运行:
二:一个生产者、一个消费者、N个资源情况
这里资源用是一个数组代替了。其实本质上和上面类似,每次只让生产者或消费者中的一个进入,进入后放到哪个地方或从哪个地方取就得用一个标志来说明了,其实也可以为每一资源加上信号量的。
这里在生产者和消费者那里都设置了一个static的变量当做游标,指示下个资源放到哪个位置和下次从哪取资源。staitic变量用在这里很合适,因为只会初始化一次。
#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>#define N 5int semInite(int semId, int value); int semDelete(int semId); int semP(int semId); int semV(int semId);//declare a union to be used union 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 declare static int semFullId; static int semEmptyId; static int srcArr[N]; //source definition //new thread as a consumer void* child_thread(void* arg) {int ttt = 1;while(1){static int pToGet = 0; //get source from the positionsleep(rand() % 19);printf("child No.%d times wants to consume(get from index %d)...\n", ttt, pToGet);semP(semFullId); // printf("child No.%d times start consuming.(get from index %d, data is %d)\n", ttt, pToGet, srcArr[pToGet]);srcArr[pToGet] = 0;printf("child No.%d times end consuming. (get from index %d)\n\n", ttt++, pToGet);pToGet = (pToGet + 1) % N;semV(semEmptyId); // }return (void*)0; }int main(void) { //create semaphoresemFullId = semget((key_t)1235, 1, 0666 | IPC_CREAT);semEmptyId = semget((key_t)1236, 1, 0666 | IPC_CREAT);semInite(semFullId, 0);semInite(semEmptyId, N); //N source pthread_t pid;pthread_create(&pid, NULL, child_thread, NULL);int tt = 1; while(1){static int pToPut = 0; //next position where source to be filled insleep(rand() % 18);printf("parent No.%d times wants to produce(put in %d index)...\n", tt, pToPut);semP(semEmptyId); // printf("parent No.%d times start producing.(put in %d index, original data is %d)\n", tt, pToPut, srcArr[pToPut]);int temp = rand() % 100;srcArr[pToPut] = temp;printf("parent No.%d times end producing.(put in %d index, now data is %d)\n", tt++, pToPut, srcArr[pToPut]);pToPut = (pToPut + 1) % N;semV(semFullId); // }semDelete(semFullId);semDelete(semEmptyId);return 0; }//set semaphore as default value int semInite(int semId, int value) {union semun semUnion;semUnion.val = value; //set default semaphorereturn semctl(semId, 0, SETVAL, semUnion); }//delete semaphore int semDelete(int semId) {union semun semUnion;return semctl(semId, 0, IPC_RMID, semUnion); }//semaphore P operation int semP(int semId) {struct sembuf semBuf;semBuf.sem_num = 0; //indicate it is not semaphore arraysemBuf.sem_op = -1; //subtract onesemBuf.sem_flg = SEM_UNDO;return semop(semId, &semBuf, 1); //return value }//semaphore V operation int semV(int semId) {struct sembuf semBuf;semBuf.sem_num = 0; //indicate it is not semaphore arraysemBuf.sem_op = 1; //subtract onesemBuf.sem_flg = SEM_UNDO;return semop(semId, &semBuf, 1); //return value }
222
运行结果:
三:N个生产者,N个消费者,N个资源
这种情况不仅生产者和消费者之间要通过上述的方式协调使用资源,而且生产者内部和消费者内部也要协调。定义四个信号量:
empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。
mutex1——生产者之间的互斥信号量,初值为1。
mutex2——消费者之间的互斥信号量,初值为1。
//生产者进程 P(mutex1)P(empty)生产数据并放进特定位置V(full) V(mutex1)//消费者进程 P(mutex2)P(full)消费数据V(empty) V(mutex2)
其实上面生产者或者消费者获取互斥量或信号量的顺序可以颠倒的,不会产生死锁。
当然这个问题可以用其他更好的方式解决,我还得继续学习。
转载于:https://www.cnblogs.com/jiayith/p/3854312.html
Linux 信号量 生产者消费者小例题相关推荐
- [Linux]生产者消费者模型(基于BlockQueue的生产者消费者模型 | 基于环形队列的生产者消费者模型 | 信号量 )
文章目录 生产者消费者模型 函数调用角度理解生产者消费者模型 生活角度理解生产者消费者模型 为什么要使用生产者消费者模型 生产者消费者模型优点 321原则 基于BlockingQueue的生产者消费者 ...
- Linux 实验:记录型信号量 生产者-消费者问题详解
进程同步问题是一个非常重要且相当有趣的问题,因而吸引了很多学者对他进行研究.本文就选取其中较为代表性的生产者-消费者问题来进行学习,以帮助我们更好的理解进程同步的概念及实现方法. 一.问题描述 有一群 ...
- 【Linux】生产者消费者编程实现-线程池+信号量
生产者消费者编程实现,采用了线程池以及信号量技术. 线程的概念就不多说,首先说一下多线程的好处:多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞 ...
- windows下如何进行linux编程,生产者-消费者问题编程简单实现--windows和linux下
又是某课程的实验(感觉好烦啊啊...),这次终于不用编译内核了,但是但是,他让我们写多线程.好吧,那就写写写,但是等等..他要我们实现生产者-消费者同步问题,要用信号量解决同步问题..这几个都是什么鬼 ...
- Linux下生产者消费者问题的C语言实现
注:查看全文请关注作者,或点击前往:生产者-消费者问题的C语言实现 实验六 生产者-消费者问题实现 实验题目 要求 在Linux操作系统下用C实现经典同步问题:生产者-消费者,具体要求如下: (1) ...
- day 34 守护线程守护进程 互斥锁线程 信号量 生产者消费者
今日内容 1.守护进程vs 守护线程(*) 2.互斥锁(**) 3.信号量(**) 4.生产者消费者模型(*****) 5.GIL(什么时候用进程,什么时候用线程)(*****) 一.守护进程和守护线 ...
- Linux多线程——生产者消费者模型
目录 一.生产者消费者模型 1.1 什么是生成者消费者模型 1.2 生产者消费者模型的优点 1.3 基于阻塞队列实现生产者消费者模型 1.4 POSIX信号量 1.4.1 信号量概念 1.4.2 P操 ...
- 【Linux】生产者消费者模型
文章目录 一. 什么是生产者消费者模型 1. 基本概念 2. 三种关系 3. 再次理解生产者消费者模型 二. 生产者消费者模型的优点 三. 基于BlockingQueue的生产者消费者模型 1. 准备 ...
- 【Linux】生产者消费者模型-基于环形队列实现
1.环形缓冲区的优势 在上篇博客基于阻塞队列的生产者消费者模型中我介绍了什么是生产者消费者模型以及生产者-消费者模式,还没了解的可以戳链接查看. 基于阻塞队列的实现,虽然简单,但是对内存分配性能要求较 ...
最新文章
- 数据蒋堂 | 数据分布背后的逻辑
- mysql的trim动态标签_Mybatis之trim标签的理解
- 用计算机完成下表的视距测量计算公式,测量学计算题.doc
- 配置mysql为主主复制步骤
- 数据结构与索引-- B+树索引
- C# .NET 使用 NPOI 生成 .xlsx 格式 Excel
- “贵妇”必备的高价糖水,我给燕窝上了10年智商税
- HCIE Security 常见WEB攻击 备考笔记(幕布)
- Mac音量微调技巧:如何一点一点的加音量或者减呢?
- Request.GetOwinContext()打不到
- ubuntu安装eclipse教程
- 【机器学习】PRC(PR曲线)
- MP3中设置播放顺序的软件《闪存式MP3伴侣》
- ps渐变如何使用?如何使用Photoshop 2021给图片制作出渐变效果?
- less文件中导入另一个less文件
- 有一种努力叫“凌晨四点”
- 【JavaSE】继承基本使用
- 开发制作一个小程序需要多少钱
- 我在达芬奇的笔记本里,找到了用户画像的起源
- 不一样的课程表,不一样的Excle--用Excle进行设计(42):排序所演绎的数据逻辑
热门文章
- 理解js中的原型链,prototype与__proto__的关系
- Objective-C中的@property和@synthesize用法
- Aspose.Java实现word转pdf,添加水印等操作
- Linux 从头学 01:CPU 是如何执行一条指令的?
- 数据结构——链式队列解析(C语言版)
- C语言写文件到txt里有屯字,C语言10 文件.ppt
- php生成文件index.html,Typecho生成静态首页index.html文件
- java代码块的定义_Java几种代码块的定义与常见问题
- MVC实现实现文件流打包成压缩包
- 云上城之个服务器维护时间,云上城之歌寒冬边界开服时间表_云上城之歌新区开服预告_第一手游网手游开服表...