生产者-消费者模式的简介:

在实际的软件开发过程中,我们将产生数据的模块称为生产者,处理数据的模块成为消费者。但仅有这两者还不够成为一个生产者-消费者模式,还需要有一个缓冲区(一段内存区域)作为中介,生产者产生的数据放入缓冲区,消费者从缓冲区读取数据并处理。(注:上述所说的模块是广义的,可以是类,函数,线程,进程等)

我们可以将这二者之间的关系图表示出来:

总结:我们用3-2-1的方法来简单描述一个生产者-消费者模式,3代表有三种关系:生产者-生产者,消费者-消费者,生产者-消费者;2代表两个角色:生产者,消费者;1代表一个交易场所:缓冲区

生产者-消费者模式之间的三种关系:

模拟实现生产者-消费者模式之前,我们需要先捋清除这之间的关系:

  • 生产者-生产者:很明显,这两者之间必定是一种竞争关系,也就是说一个生产者往缓冲区放数据时另一个生产者就不能去访问这块空间
  • 消费者-消费者:同样,两个消费者之间也是竞争的关系,这就好比两个人同时看中一件商品时,他们之间就是一种竞争的关系
  • 生产者-消费者:生产者与消费者之间其实是一种同步与互斥的关系,假设只有一个生产者一个消费者时,只有生产者放入数据后消费者才能读取,消费者拿到数据后生产者才去生产,这就是一种同步;但当生产者生产数据的时候消费者就不能从缓冲区拿数据,或者消费者读数据的时候生产者就不能往缓冲区里写数据,否则很可能会导致两者都存/取数据失败,产生二义性问题。

生产者-单消费者的实现:

  • 方案一:使用互斥锁+条件变量
    我们现在模拟一个场景,生产者将生产的数据放入交易场所,消费者从中读取。这个场所我们就用单链表来模拟(它还可以是任意一个数据结构,只要能够存储数据),生产者放入数据时进行头插,消费者消费数据时进行头删(这里我采用的是头插头删的方式,当然也可以用尾插、尾删的方式实现):

既然已经确定了生产场所,其次我们要考虑到如何才能让这二者时间实现同步与互斥。多线程编程中提到了“条件变量(Condition Variable)”,在此,我们再次简单回顾一下这几个函数:(文章链接:http://blog.csdn.net/qq_33951180/article/details/72801651)

//初始化一个条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);  //销毁一个条件变量
int pthread_cond_destroy(pthread_cond_t *cond);  //唤醒等待的线程
int pthread_cond_signal(pthread_cond_t *cond); //唤醒一个
int pthread_cond_broadcast(pthread_cond_t *cond);  //唤醒所有//阻塞等待
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
//设定超时等待
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,  const struct timespec *restrict abstime);  

我们可以利用条件变量中的相关函数来模拟实现,当生产者线程生产数据时消费者线程就wait,当消费者被唤醒后,此时链表已经有数据(消费者等待成功),拿走结点;消费者读取数据的过程中生产者在wait,等到消费者读取数据完之后被唤醒,然后继续往缓冲区写入数据(循环………),等待与被唤醒的过程就可以利用上述的pthread_cond_wait和pthread_cond_signal函数实现。

代码以托管到github:
https://github.com/lybb/Linux/tree/master/Product_Consumer/product_consumer_2_19

  • 方案二:使用信号量实现
    我们将方案一中的链表这次该为环形队列,环形队列使用数组模拟实现(循环链表也可以),如图:

我们将数组想象成上图中的环形队列,生产者和消费者都从0号下标的位置开始走,一开始,环形队列中有N个空格子和0个数据,因此,在生产者没有生产数据之前,消费者是不能进行消费的;
当生产者生产的数据占满整个环形buf时,假设消费者还在0号位置,生产者和消费者就会再次在0号位置相遇,此时有0个block资源和N个data资源,因此生产不能继续放入数据;
当消费者和生产者都在执行时,一旦消费者追上了生产者,消费者就没有资源可供使用了。

综上:使用环形buf的情况下,生产者和消费者必须满足:
①一开始,必须保证生产者先运行;
②生产者不能将消费者套圈(参考上述第二点);
③消费者不能追上生产者(参考第三点)

对于生产者来说:只关心空格子(block)资源
对于消费者来说:只关心数据(data)资源

因此,我们在用信号量实现时,需要两个信号量来分别表示block和data资源。

代码上传至github:
https://github.com/lybb/Linux/tree/master/Product_Consumer/Ring

  • 两种实现方案的比较:
    互斥锁+条件变量实现的是有锁同步,而信号量实现的是无锁同步

多线程实现生产者与消费者模式相关推荐

  1. 多线程通信—生产者和消费者模式

    1.队列Queue: 从一个线程向另一个线程发送数据最安全的方式可能就是使用queue库中的队列了.创建一个被多个线程共享的Queue对象,这些线程通过使用put()和get()操作来向队列中添加或者 ...

  2. Java并发编程系列18:多线程之生产者和消费者模式_信号灯法(wait/notify通知机制)

    1.生产者消费者模式 生产者消费者问题(Producer-consumer problem),也称为有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题 ...

  3. python 生产者和消费者模式_Python爬虫:生产者和消费者模式

    认识生产者和消费者模式 生产者和消费者是多线程中很常见的一个问题.产生数据的模块,我们称之为生产者,而处理数据的模块,就称为消费者.但是单单只有生产者和消费者显然还是不够的,一般来说,我们还有一个缓冲 ...

  4. 认识生产者和消费者模式

    认识生产者和消费者模式 生产者和消费者是多线程中很常见的一个问题.产生数据的模块儿,我们称之为生产者,而处理数据的模块,就称为消费者.但是单单只有生产者和消费者显然还是不够的,一般来说,我们还有一个缓 ...

  5. python 多线程并发编程(生产者、消费者模式),边读图像,边处理图像,处理完后保存图像实现提高处理效率

    文章目录 需求 实现 先导入本次需要用到的包 一些辅助函数 如下函数是得到指定后缀的文件 如下的函数一个是读图像,一个是把RGB转成BGR 下面是主要的几个处理函数 在上面几个函数构建对应的处理函数 ...

  6. Java基础进阶多线程-生产者和消费者模式

    1.什么是"生产者和消费者模式"? 生产线程负责生产,消费线程负责消费 生产线程和消费线程要达到均衡 这是一种特殊的业务需求,在这种特殊的情况下需要使用wait方法和notify方 ...

  7. Python中的生产者与消费者模式(转载)

    利用多线程和队列可以实现生产者消费者模式.该模式通过平衡生产线程和消费线程的工作能力来提高程序整体处理数据的速度. 1.什么是生产者和消费者? 在线程世界里,生产者就是生产数据(或者说发布任务)的线程 ...

  8. Java多线模式-Producer-Consumer模式(生产者、消费者模式)

    1.场景 有些时候需要两个或两个以上的线程协同工作,每个线程需要使用其他线程产生数据. 2.详细说明 可以把上面的场景抽象成生产者和消费者模式.从消费者的角度:消费者需要消费生产者生成的产品. 从生产 ...

  9. 线程间的协作(2)——生产者与消费者模式

    2019独角兽企业重金招聘Python工程师标准>>> 1.何为生产者与消费者 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程. import java.util. ...

最新文章

  1. Newtonsoft.Json code
  2. 提高网站有效流量从三个方面出发
  3. 屏幕旋转的处理方法,实现视图位置的变化
  4. AI:2020年6月22日北京智源大会演讲分享之09:00-09:50 全体大会《AI精度与隐私的博弈》
  5. 江苏小米授权维修商网点收藏
  6. 谁都忍不了烂代码,如何用重构的方式让它整洁起来?
  7. 最佳实践丨三种典型场景下的云上虚拟IDC(私有池)选购指南
  8. 润乾报表分组求和_一招搞定各种报表合计需求
  9. 小c下载样式插件Xiaocstyle适用于emlog系统
  10. 智能贴图样机素材在手,海报逼格马上就有!
  11. 慕课学习--DNS的作用
  12. 嵌入式linux实验一vim的使用,嵌入式Linux C语言开发工具—vi/vim实训操作
  13. Oracle 在安装时,安装文件的目录不能有汉字。
  14. HDU 1325 Is It A Tree?(并查集)
  15. linux多个svn仓库权限管理,svn建立仓库而且设置用户的权限
  16. 分享hm77芯片组bios工具 联想m490添加inter7265ac 白名单bios
  17. 存储服务器2012R2系统怎么搞文件共享,server2012r2文件共享局域网权限设置的方法...
  18. JQuery模拟MAC任务栏放大效果
  19. cesium实现运动模型的相机上帝视角跟随
  20. 趣图:代码突然又可以运行了,why?

热门文章

  1. idea像eclipse一样显示多个project
  2. Jenkins 流水线自动化部署 Go 项目
  3. Grafana 导出所有dashboard
  4. 比较有效的Windows10卡硬盘解决方法
  5. java freemind_java环境变量的应用:为Freemind配置Java环境
  6. hackyou2014 CTF web关卡通关攻略
  7. 网站卡其cdn后不能访问_网站使用CDN加速后,网站无法访问如何解决
  8. Linux下for语句
  9. chromebook刷机_某些Chromebook无法获得Linux应用。 这是您可以做的
  10. 小学四年级计算机上册考试试题,小学四年级数学上册复习试题