Linux组件封装(五)一个生产者消费者问题示例
生产者消费者问题是计算机中一类重要的模型,主要描述的是:生产者往缓冲区中放入产品、消费者取走产品。生产者和消费者指的可以是线程也可以是进程。
生产者消费者问题的难点在于:
为了缓冲区数据的安全性,一次只允许一个线程进入缓冲区,它就是所谓的临界资源。
生产者往缓冲区放物品时,如果缓冲区已满,那么需要等待,一直到消费者取走产品为止。
消费者取走产品时,如果没有物品,需要等待,一直到有生产者放入为止。
第一个问题属于互斥问题,我们需要使用一把互斥锁,来实现对缓冲区的安全访问。
后两个属于同步问题,两类线程相互协作,需要两个条件变量,一个用于通知生产者放入产品,一个用来通知消费者取走物品。
生产者线程的大概流程是:
1.加锁
2.如果缓冲区已满,则等待。
3.放入物品
4.解锁
5.通知消费者,可以取走产品
消费者的逻辑恰好相反:
1.加锁
2.缓冲区为空,等待
3.取走物品
4.解锁
5.通知生产者,可以放入物品
我们设计出一个缓冲区:
#ifndef BUFFER_H_
#define BUFFER_H_ #include "NonCopyable.h"
#include "MutexLock.h"
#include "Condition.h"
#include <queue> class Buffer : NonCopyable
{
public:
Buffer(size_t size);
void push(int val);
int pop(); bool empty() const;
size_t size() const; private:
mutable MutexLock mutex_;
Condition full_;
Condition empty_; size_t size_; //缓冲区的大小
std::queue<int> queue_;
}; #endif //BUFFER_H_
这里注意,我们把同步与互斥的操作都放入Buffer中,使得生产者和消费者线程不必考虑其中细节,这符号软件设计的“高内聚、低耦合”原则。
还有一点,mutex被声明为mutable类型,意味着mutex在const函数中仍然可以被改变,这是符合程序的逻辑的。把mutex声明为mutable,是一种标准实践。
重点是push和pop的实现:
void Buffer::push(int val)
{
//lock
//wait
//push
//notify
//lock
{
MutexLockGuard lock(mutex_);
while(queue_.size() >= size_)
empty_.wait();
queue_.push(val);
}
full_.notify();
} int Buffer::pop()
{
int temp = 0;
{
MutexLockGuard lock(mutex_);
while(queue_.empty())
full_.wait();
temp = queue_.front();
queue_.pop();
}
empty_.notify(); return temp;
}
这里注意:
1.条件变量的等待必须使用while,这是一种最佳实践,原因可见Condition的封装Linux组件封装(二)中条件变量Condition的封装。
2.可以先notify再解锁,也可以先解锁。不过推荐先解锁,原因是如果先notify,唤醒一个线程B,但是还未解锁,此时如果线程切换至刚唤醒的线程B,B马上尝试lock,但是肯定失败,然后阻塞,这增加了一次线程切换的开销。
我们还可以继续封装,将缓冲区与多个生产者、消费者封装成一个车间类,如下:
#ifndef WORKSHOP_H_
#define WORKSHOP_H_ #include "NonCopyable.h"
#include "Buffer.h"
#include <vector> class ProducerThread;
class ConsumerThread; class WorkShop : NonCopyable
{
public:
WorkShop(size_t bufferSize,
size_t producerSize,
size_t consumerSize);
~WorkShop(); void startWorking();
private:
size_t bufferSize_;
Buffer buffer_; size_t producerSize_;
size_t consumerSize_;
std::vector<ProducerThread*> producers_;
std::vector<ConsumerThread*> consumers_;
}; #endif //WORKSHOP_H_
这样就可以方便的指定线程的数目。
完整的项目代码请参见这里:生产者消费者完整代码
Linux组件封装(五)一个生产者消费者问题示例的更多相关文章
- 并发编程(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题
请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比" ...
- 并发编程入门(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题
请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比" ...
- Linux多线程之同步2 —— 生产者消费者模型
思路 生产者和消费者(互斥与同步).资源用队列模拟(要上锁,一个时间只能有一个线程操作队列). m个生产者.拿到锁,且产品不满,才能生产.当产品满,则等待,等待消费者唤醒.当产品由空到不空,通知消费者 ...
- 五、生产者消费者模型_ThreadLocal
1.生产者消费者模型作用和示例如下:1)通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率 ,这是生产者消费者模型最重要的作用2)解耦,这是生产者消费者模型附带的作用,解耦意味着生产者 ...
- 用阻塞队列实现一个生产者消费者模型?synchronized和lock有什么区别?
多线程当中的阻塞队列 主要实现类有 ArrayBlockingQueue是一个基于数组结构的有界阻塞队列,此队列按FIFO原则对元素进行排序 LinkedBlockingQueue是一个基于链表结构的 ...
- 用Java写一个生产者-消费者队列
生产者消费者的模型作用 通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率,这是生产者消费者模型最重要的作用. 解耦,这是生产者消费者模型附带的作用,解耦意味着生产者和消费者之间的联系 ...
- golang的生产者消费者模型示例
package main import "fmt" func Producer(ch chan int) { for i := 1; i <= 10; i++ { ch &l ...
- Python 再次改进版通过队列实现一个生产者消费者模型
import time from multiprocessing import Process,Queue #生产者 def producer(q): for i in range(10): time ...
- Linux组件封装(一)中互斥锁MutexLock的封装
本文对Linux中的pthread_mutex_t做一个简易的封装. 互斥锁主要用于互斥,互斥是一种竞争关系,主要是某一个系统资源或一段代码,一次做多被一个线程访问. 条件变量主要用于同步,用于协调线 ...
随机推荐
- MyBatis的常见错误总结
把MyBatis的常见错误总结一下.. UserMapper: <mapper namespace="com.ydweb.data.dao.UserMapper"> & ...
- UVALIVE 2431 Binary Stirling Numbers
转自别人的博客.这里记录一下 这题是定义如下的一个数: S(0, 0) = 1; S(n, 0) = 0 for n > 0;S(0, m) = 0 for m > 0; S(n, m) ...
- 跨平台的EVENT事件 windows linux
#ifndef _HIK_EVENT_H_ #define _HIK_EVENT_H_ #ifdef _MSC_VER #include <Windows.h> #define hik_e ...
- 一个boost底下的线程池
Boost的thread库中目前并没有提供线程池,我在sorceforge上找了一个用boost编写的线程池.该线程池和boost结合的比较好,并且提供了多种任务执行策略,使用也非常简单. 下载地址: ...
- 制作servlet模板
制作servlet模板 选中window-->preference--->搜索template--->选中java下面的template new一个 Name的设置,当你在eclip ...
- js面试总结
<div id="app"> <button onClick="app()">点击1</button> <button ...
- Codeforces Round #445 C. Petya and Catacombs【思维/题意】
C. Petya and Catacombs time limit per test 1 second memory limit per test 256 megabytes input standa ...
- POJ 2135 Farm Tour (费用流)
[题目链接] http://poj.org/problem?id=2135 [题目大意] 有一张无向图,求从1到n然后又回来的最短路 同一条路只能走一次 [题解] 题目等价于求从1到n的两条路,使得两 ...
- [POI2014]Criminals
题目大意: 给你一个长度为$n(n\le10^6)$的颜色序列,其中每个颜色互不相同.两个人$A$和$B$分别从某个点出发从左往右.从右往左任意地选择颜色,然后在中间的某一点相遇.分别给出两人所选择的 ...
- linux coreseek-4.1安装
1.假设已经有coreseek-4.1-beta.tar.gz源文件 [root@qp232 ~]# cd /usr/local [root@qp232 local]# tar -zxvf /yd/l ...