博客
关于我
Linux系统编程40:多线程之基于环形队列的生产者与消费者模型
阅读量:207 次
发布时间:2019-02-28

本文共 2938 字,大约阅读时间需要 9 分钟。

文章目录

(1)什么是信号量

前面的叙述中,我们通过锁保证了每次只有一个线程进入临界区,但是临界区资源很多也很大,每次只允许一个线程进入往往会使效率很低。所以如果将临界区划分为多个独立的区域,划分为多少个区域就让多少个线程进入,,但是这样就同时带来了一个问题——如果划分为了5个区域,但是同时进入了10个线程该怎么办?所以这一点可以通过信号量解决。信号量可以理解为一个计数器,它用来描述临界资源的有效个数

信号量由一个值和一个指针组成,指针指向等待该信号量的线程。信号量的值表示相应资源的使用情况,比如如果S>=0表示资源够用,如果执行P操作表示请求分配一个资源,那么S就会减一;当S<0时表示已经没有可用资源(此时S的绝对值表示等待该资源的线程数)请求者必须等待其他线程释放资源方可继续运行。如果执行一个V操作就表示会释放一个资源,所以S加一

(2)与信号量相关的操作

1:要使用信号量就需要创建一个sem_t类型变量

#include 
//头文件sem_t sem1;

2:在使用信号量前,需要对这个变量进行初始化,使用的函数是sem_init

int sem_init(sem_t* sem,int pshared,unsigned int value);//pshared一般给0,非零表示进程间共享//value:信号量初始值

3:信号量使用完毕需要用sem_destory进行销毁

int sem_destory(sem_t* sem);

4:POSIX信号量中的P操作对应的接口是sem_waitm,V操作对应的接口是sem_post

int sem_wait(sem_t* sem);int sem_post(sem_t* sem);

(3)基于环形队列的生产者与消费者模型-信号量(单消费者单生产者)

基于阻塞队列的生产者与消费者模型存在一个很大的问题就是他们其实是在串行运行的,并没有并行运行,这就导致他们的效率不是很高,而使用环形队列则可以解决这个问题。

在这里,我们使用的载体是环形队列,他和数据结构的循环队列基本一致,在这里就不做过多介绍了,具体请移步

如下在这样的模型中,消费者和生产者都有各自的P,V操作,消费者关心的是队列中有没有数据,所以它进行P操作时申请的是数据,而进行V操作时归还的是空格资源;生产者关系的是队列中有没有空格,所以它进行P操作时申请的是空格,而进行V操作时由于生产好了数据归还的就是数据

在这里插入图片描述

这样的模型为什么可以实现并行操作呢?举例来说,当消费者和生产者启动时,由于队列中全部为空,所以即便消费者先运行它也会因为没有数据而被挂起,所以生产者就会先运行生产数据。一旦产生了数据,数据的信号量增加,于是消费者拿掉信号进行消费,一旦所有空格都存放了数据,那么生产者就会挂起,当消费者消费完一个数据,然后归还空格,于是生产者又会拿到信号启动生产。这样,只要队列中同时有空格和数据,生产者和消费者就能同时运行
在这里插入图片描述
如下,我们使用POSIX信号量。利用唤醒队列重写这个消费者生产者模型。
circular_queue.hpp如下
在这里插入图片描述

#include 
#include
#include
#include
using namespace std;class CircularQueue{ private: vector
v;//用作循环队列 int _cap;//队列大小 sem_t data;//消费者信号量(消费者关注数据数量) sem_t blank;//生产者信号量(生产者关注空格数量) int com_index;//消费者的索引 int pro_index;//生产者的索引public: CircularQueue(int cap=10):_cap(cap) { v.resize(_cap); sem_init(&data,0,0);//初始化消费者信号量 sem_init(&blank,0,_cap);///初始化生产者信号量 com_index=0; pro_index=0;//索引开始时都指向0 } ~CircularQueue() { sem_destroy(&data);//销毁信号量 sem_destroy(&blank); } void Put(const int& val)//生产者存放数据 { sem_wait(&blank);//P操作,生产者申请的是空格资源 v[pro_index]=val; pro_index++; pro_index%=_cap;//环形队列 sem_post(&data);//V操作,生产者释放的数据 } void Get(int& val)//消费者取数据 { sem_wait(&data);//P操作,消费者申请的是数据 val=v[com_index]; com_index++; com_index%=_cap;//环形 sem_post(&blank);//V操作,消费者释放的是空格 }};

test.cpp如下

#include "circular_queue.hpp"#include 
CircularQueue* bq=new CircularQueue(10);void* consumer_run(void* arg){ while(1) { int data; bq->Get(data); printf("%s拿到数据:%d\n",(char*)arg,data); }}void* productor_run(void* arg){ int cout=1; while(1) { if(cout==11) cout=1; bq->Put(cout); printf("%s放进数据:%d\n",(char*)arg,cout); cout++; sleep(1); }}int main(){ pthread_t con,pro; pthread_create(&con,nullptr,consumer_run,(void*)"消费者"); pthread_create(&pro,nullptr,productor_run,(void*)"生产者"); pthread_join(con,nullptr); pthread_join(pro,nullptr); delete bq; return 0;}

效果如下,在这里限制生产者的速度,所以每当生产者生产一个的时候消费者才能消费。更多的时候,消费者生产者是并行的

(生产者慢,消费者快)
在这里插入图片描述

转载地址:http://visi.baihongyu.com/

你可能感兴趣的文章
ngrok内网穿透可以实现资源共享吗?快解析更加简洁
查看>>
NHibernate动态添加表
查看>>
NHibernate学习[1]
查看>>
NHibernate异常:No persister for的解决办法
查看>>
Nhibernate的第一个实例
查看>>
NHibernate示例
查看>>
nid修改oracle11gR2数据库名
查看>>
NIFI1.21.0/NIFI1.22.0/NIFI1.24.0/NIFI1.26.0_2024-06-11最新版本安装_采用HTTP方式_搭建集群_实际操作---大数据之Nifi工作笔记0050
查看>>
NIFI1.21.0_java.net.SocketException:_Too many open files 打开的文件太多_实际操作---大数据之Nifi工作笔记0051
查看>>
NIFI1.21.0_Mysql到Mysql增量CDC同步中_日期类型_以及null数据同步处理补充---大数据之Nifi工作笔记0057
查看>>
NIFI1.21.0_Mysql到Mysql增量CDC同步中_补充_插入时如果目标表中已存在该数据则自动改为更新数据_Postgresql_Hbase也适用---大数据之Nifi工作笔记0058
查看>>
NIFI1.21.0_Mysql到Mysql增量CDC同步中_补充_更新时如果目标表中不存在记录就改为插入数据_Postgresql_Hbase也适用---大数据之Nifi工作笔记0059
查看>>
NIFI1.21.0_NIFI和hadoop蹦了_200G集群磁盘又满了_Jps看不到进程了_Unable to write in /tmp. Aborting----大数据之Nifi工作笔记0052
查看>>
NIFI1.21.0_Postgresql和Mysql同时指定库_指定多表_全量同步到Mysql数据库以及Hbase数据库中---大数据之Nifi工作笔记0060
查看>>
NIFI1.21.0最新版本安装_连接phoenix_单机版_Https登录_什么都没改换了最新版本的NIFI可以连接了_气人_实现插入数据到Hbase_实际操作---大数据之Nifi工作笔记0050
查看>>
NIFI1.21.0最新版本安装_配置使用HTTP登录_默认是用HTTPS登录的_Https登录需要输入用户名密码_HTTP不需要---大数据之Nifi工作笔记0051
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_增删改数据分发及删除数据实时同步_通过分页解决变更记录过大问题_02----大数据之Nifi工作笔记0054
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_增加修改实时同步_使用JsonPath及自定义Python脚本_03---大数据之Nifi工作笔记0055
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_插入修改删除增量数据实时同步_通过分页解决变更记录过大问题_01----大数据之Nifi工作笔记0053
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表或全表增量同步_实现指定整库同步_或指定数据表同步配置_04---大数据之Nifi工作笔记0056
查看>>