本文首发于个人博客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

History

  • 20191012: created.

Copyright

C++ 如何用百行代码实现线程安全的并发队列 | concurrent queue or blocking queue implemented in cpp的更多相关文章

  1. JELLY技术周刊 Vol.24 -- 技术周刊 &#183; 实现 Recoil 只需百行代码?

    蒲公英 · JELLY技术周刊 Vol.24 理解一个轮子最好的方法就是仿造一个轮子,很多框架都因此应运而生,比如面向 JS 开发者的 AI 工具 Danfo.js:参考 qiankun 的微前端框架 ...

  2. 继续node爬虫 — 百行代码自制自动AC机器人日解千题攻占HDOJ

    前言 不说话,先猛戳 Ranklist 看我排名. 这是用 node 自动刷题大概半天的 "战绩",本文就来为大家简单讲解下如何用 node 做一个 "自动AC机&quo ...

  3. 几百行代码写个Mybatis,原理搞的透透的!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 Mybatis 最核心的原理也是它最便于使用的体现,为什么这说? 因为我们在使用 M ...

  4. 几百行代码实现一个 JSON 解析器

    前言 之前在写 gscript时我就在想有没有利用编译原理实现一个更实际工具?毕竟真写一个语言的难度不低,并且也很难真的应用起来. 一次无意间看到有人提起 JSON 解析器,这类工具充斥着我们的日常开 ...

  5. IOS 作业项目(1) 关灯游戏 (百行代码搞定)

    1,准备工作,既然要开关灯,就需要确定灯的灯的颜色状态 首先想到的是扩展UIColor

  6. Redux百行代码千行文档

    接触Redux不过短短半年,从开始看官方文档的一头雾水,到渐渐已经理解了Redux到底是在做什么,但是绝大数场景下Redux都是配合React一同使用的,因而会引入了React-Redux库,但是正是 ...

  7. 一个几百行代码实现的http服务器tinyhttpd

    /* J. David's webserver */ /* This is a simple webserver. * Created November 1999 by J. David Blacks ...

  8. 百行go代码构建p2p聊天室

    百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...

  9. 以太坊系列之十八: 百行go代码构建p2p聊天室

    百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...

随机推荐

  1. Wireshark数据包分析入门

    Wireshark数据包分析(一)——使用入门   Wireshark简介: Wireshark是一款最流行和强大的开源数据包抓包与分析工具,没有之一.在SecTools安全社区里颇受欢迎,曾一度超越 ...

  2. Linux三剑客之awk命令详解

    一.awk介绍 AWK是一种优良的文本处理工具.它不仅是 Linux 中也是任何环境中现有的功能最强大的数据处理引擎之一.这种编程及数据操作语言(其名称得自于它的创始人 Alfred Aho .Pet ...

  3. PythonI/O进阶学习笔记_8.python的可迭代对象和迭代器、迭代设计模式

     content: 1.什么是迭代协议 2. 什么是迭代器(Iterator)和可迭代对象(Iterable) 3. 使用迭代器和可迭代对象 4. 创建迭代器和可迭代对象 5. 迭代器设计模式   一 ...

  4. C#获取字符串的拼音和首字母

    在C#中我们想要获取字符串的拼音并不是那么困难的,在网上看到很多都是特别笨的方式来实现,其实各有各的好处吧,如果使用了下方法方式,它不知道多音字,这就是一个问题. /// <summary> ...

  5. MongoDB 快速扫盲贴

    长话短说 经过996的历练,开发者潜意识里总是以object的视角看待事物, 现在某些数据库也具备这样的视角. MongoDB是一个文档型(类JSON 文档)数据库,相比传统的关系型row/colum ...

  6. [译]C# 7系列,Part 3: Default Literals 默认文本表达式

    原文:https://blogs.msdn.microsoft.com/mazhou/2017/06/06/c-7-series-part-3-default-literals/ C#的default ...

  7. c++-面向对象:类和对象

    类和对象 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string.h> using names ...

  8. Linux中防火墙命令

    #启动   systemctl start firewalld #开机启动   systemctl enable firewalld #停止   systemctl stop firewalld #禁 ...

  9. IT兄弟连 HTML5教程 CSS3属性特效 渐变1

    渐变背景一直以来在Web页面中都是一种常见的视觉元素.但一直以来,Web设计师都是通过图形软件设计这些渐变效果,然后以图片形式或者背景图片的形式运用到页面中.Web页面上实现的效果,仅从页面的视觉效果 ...

  10. idea自用快捷键(非常实用)

    最近看了下idea的快捷键,不禁感慨idea真是太强大了,这里记录一下我常用的快捷键 Ctrl+F:在当前文件中查找 Ctrl+R:替换字符串 Alt + shift + 鼠标点击   多处同时编辑 ...