C++ 如何用百行代码实现线程安全的并发队列 | concurrent queue or blocking queue implemented in cpp
本文首发于个人博客https://kezunlin.me/post/cabccf5c/,欢迎阅读最新内容!
concurrent queue or blocking queue implemented in cpp
Guide
introduction
Where produce-consumer pattern is present it is often the case that one is faster that the other:
- a parsing producer reads records faster than a processing consumer;
- a disk reading producer is faster than network sending consumer.
Producer and consumer often communicate by queues: the producer will put items on a queue while the consumer will pop items off a queue. What happens when the queue becomes full, or empty?
One approach of the producer is to try to put an item on a queue and if it’s full yield the thread and repeat. Similarly the consumer can try to pop an item off a queue and if it’s empty, ditto. This approach of try-fail-yield can unnecessarily burn CPU cycles in tight loops that constantly try to put or pop items off a queue.
Another approach is to temporarily grow the queue, but that doesn’t scale well. When do we stop growing? And once we stop we have to fall back onto the try-fail-yield method.
What if we could implement a blocking queue:
- a queue who’s put operation blocks when the queue if full, and unblocks only when another thread pops an item off the queue
- Similarly a queue who’s pop operation blocks when the queue is empty, and unblocks only when another thread puts an item on the queue.
Quote from here
An example of using such a queue would look like this (notice a fast producer and slow consumer in the code below):
blocking queue v1
//std
#include <queue>
//boost
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
namespace my {
namespace algorithm {
template<typename Data>
class SHARED_EXPORT blocking_queue
{
private:
std::queue<Data> the_queue;
mutable boost::mutex the_mutex;
boost::condition_variable the_condition_variable;
public:
void push(Data const& data)
{
boost::mutex::scoped_lock lock(the_mutex);
the_queue.push(data);
lock.unlock();
the_condition_variable.notify_one();
}
bool empty() const
{
boost::mutex::scoped_lock lock(the_mutex);
return the_queue.empty();
}
size_t size() const
{
boost::mutex::scoped_lock lock(the_mutex);
return the_queue.size();
}
bool try_pop(Data& popped_value)
{
boost::mutex::scoped_lock lock(the_mutex);
if (the_queue.empty())
{
return false;
}
popped_value = the_queue.front();
the_queue.pop();
return true;
}
void wait_and_pop(Data& popped_value)
{
boost::mutex::scoped_lock lock(the_mutex);
while (the_queue.empty())
{
the_condition_variable.wait(lock);
}
popped_value = the_queue.front();
the_queue.pop();
}
void signal_exit()
{
Data data;
push(data);
}
};
}
}// end namespace
blocking queue v2
#pragma once
#include <iostream>
#include <assert.h>
#include <queue>
#include <mutex>
#include <condition_variable>
#define MAX_CAPACITY 20
namespace my {
namespace algorithm {
template<typename T>
class SHARED_EXPORT BlockingQueue
{
public:
BlockingQueue()
:mtx(), full_(), empty_(), capacity_(MAX_CAPACITY) { }
void Push(const T& data){
std::unique_lock<std::mutex> lock(mtx);
while(queue_.size() == capacity_){
full_.wait(lock );
}
assert(queue_.size() < capacity_);
queue_.push(data);
empty_.notify_all();
}
T Pop(){
std::unique_lock<std::mutex> lock(mtx);
while(queue_.empty()){
empty_.wait(lock );
}
assert(!queue_.empty());
T front(queue_.front());
queue_.pop();
full_.notify_all();
return front;
}
T Front(){
std::unique_lock<std::mutex> lock(mtx);
while(queue_.empty()){
empty_.wait(lock );
}
assert(!queue_.empty());
T front(queue_.front());
return front;
}
T Back(){
std::unique_lock<std::mutex> lock(mtx);
while(queue_.empty()){
empty_.wait(lock );
}
assert(!queue_.empty());
T back(queue_.back());
return back;
}
size_t Size(){
std::lock_guard<std::mutex> lock(mtx);
return queue_.size();
}
bool Empty(){
std::unique_lock<std::mutex> lock(mtx);
return queue_.empty();
}
void SetCapacity(const size_t capacity){
capacity_ = (capacity > 0 ? capacity : MAX_CAPACITY);
}
private:
//DISABLE_COPY_AND_ASSIGN(BlockingQueue);
BlockingQueue(const BlockingQueue& rhs);
BlockingQueue& operator= (const BlockingQueue& rhs);
private:
mutable std::mutex mtx;
std::condition_variable full_;
std::condition_variable empty_;
std::queue<T> queue_;
size_t capacity_;
};
}
}// end namespace
Reference
- implementing-a-thread-safe-queue-using-condition-variables
- blocking-queue
- blocking_queue v1
- blocking_queue v1 Simple Blockingqueue I have used in many projects
History
- 20191012: created.
Copyright
- Post author: kezunlin
- Post link: https://kezunlin.me/post/cabccf5c/
- Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.
C++ 如何用百行代码实现线程安全的并发队列 | concurrent queue or blocking queue implemented in cpp的更多相关文章
- JELLY技术周刊 Vol.24 -- 技术周刊 · 实现 Recoil 只需百行代码?
蒲公英 · JELLY技术周刊 Vol.24 理解一个轮子最好的方法就是仿造一个轮子,很多框架都因此应运而生,比如面向 JS 开发者的 AI 工具 Danfo.js:参考 qiankun 的微前端框架 ...
- 继续node爬虫 — 百行代码自制自动AC机器人日解千题攻占HDOJ
前言 不说话,先猛戳 Ranklist 看我排名. 这是用 node 自动刷题大概半天的 "战绩",本文就来为大家简单讲解下如何用 node 做一个 "自动AC机&quo ...
- 几百行代码写个Mybatis,原理搞的透透的!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 Mybatis 最核心的原理也是它最便于使用的体现,为什么这说? 因为我们在使用 M ...
- 几百行代码实现一个 JSON 解析器
前言 之前在写 gscript时我就在想有没有利用编译原理实现一个更实际工具?毕竟真写一个语言的难度不低,并且也很难真的应用起来. 一次无意间看到有人提起 JSON 解析器,这类工具充斥着我们的日常开 ...
- IOS 作业项目(1) 关灯游戏 (百行代码搞定)
1,准备工作,既然要开关灯,就需要确定灯的灯的颜色状态 首先想到的是扩展UIColor
- Redux百行代码千行文档
接触Redux不过短短半年,从开始看官方文档的一头雾水,到渐渐已经理解了Redux到底是在做什么,但是绝大数场景下Redux都是配合React一同使用的,因而会引入了React-Redux库,但是正是 ...
- 一个几百行代码实现的http服务器tinyhttpd
/* J. David's webserver */ /* This is a simple webserver. * Created November 1999 by J. David Blacks ...
- 百行go代码构建p2p聊天室
百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...
- 以太坊系列之十八: 百行go代码构建p2p聊天室
百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...
随机推荐
- 【Java Web开发学习】Servlet、Filter、Listener
[Java Web开发学习]Servlet 转发:https://www.cnblogs.com/yangchongxing/p/9274739.html 1.Servlet package cn.y ...
- mybatis第一篇
1.mybatis介绍 1.介绍 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google co ...
- CCF-CSP题解 201703-4 地铁修建
求1-n最长边最小的路径. 最短路变形.dis值向后延申的方式是:\[dis[j]=min(dis[j],max(dis[i],w(i,j))\] 显然满足dijkstra贪心的选择方式.spfa也当 ...
- 《Java基础知识》Java接口和抽象类的区别
抽象类 抽象类必须用 abstract 修饰,子类必须实现抽象类中的抽象方法,如果有未实现的,那么子类也必须用 abstract 修饰.抽象类默认的权限修饰符为 public,可以定义为 public ...
- Docker常用命令-全
原文内容来自于LZ(楼主)的印象笔记,如出现排版异常或图片丢失等问题,可查看当前链接: https://app.yinxiang.com/shard/s17/nl/19391737/9f6bf39e- ...
- Power BI 的数据源及数据刷新
Power BI 目前可以连接超过100种数据源,包含常见的各种数据库,文件,数据仓库,云等等. 不同的数据源支持不同的连接方式,通常来讲,Power BI 支持两种数据连接方式: 导入(import ...
- linux环境下zookeeper下载安装
步骤一:安装配置jdk环境 1.下载解压jdk-8u221-linux-x64.tar.gz 2.打开 配置文件,vim /etc/profile,添加如下配置,添加完成记得source /etc/p ...
- 解决“fatal: 'origin' does not appear to be a git repository...”
当使用Git进行代码push提交时,出现报错信息“fatal: 'origin' does not appear to be a git repository...”, $ git push -u o ...
- C语言笔记 06_作用域&数组
作用域 任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问.C 语言中有三个地方可以声明变量: 在函数或块内部的局部变量 在所有函数外部的全局变量 在形式参数的函数参数定 ...
- 精通awk系列(12):awk getline用法详解
回到: Linux系列文章 Shell系列文章 Awk系列文章 getline用法详解 除了可以从标准输入或非选项型参数所指定的文件中读取数据,还可以使用getline从其它各种渠道获取需要处理的数据 ...