通过c++11的condition_variable实现的有最大缓存限制的队列
之前曾写过一个通过C++11的condition_variable实现的有最大缓存限制的队列,底层使用std::queue来实现,如果想要提升性能的话,可以考虑改用固定的长度环形数组。环形数组实现如下:
#include <cassert>
#include <type_traits>
#include <stdexcept> /*
* 文件名: circle_buffer
* 实现说明:底层使用数组来实现循环buffer
* (1) 当m_begIdx和m_endIdx相同时,表示数组为空,否则标识数组存在值
* (2) 通过预先多分配一个节点的方式,来实现存储count个元素的目的
*/ class empty_error : public std::logic_error {
explicit empty_error(const std::string& what_arg)
: logic_error(what_arg)
{} explicit empty_error(const char* what_arg)
: logic_error(what_arg)
{} }; class full_error : public std::logic_error {
explicit full_error(const std::string& what_arg)
: logic_error(what_arg)
{} explicit full_error(const char* what_arg)
: logic_error(what_arg)
{} }; template <typename T>
class circle_buffer {
public:
using size_type = size_t;
public:
explicit circle_buffer(size_type count)
: m_bufSize(count+),
m_buf(static_cast<T*>(std::malloc(sizeof(T)*m_bufSize))),
m_begIdx(),
m_endIdx()
{
assert(count >= );
if (m_buf == nullptr) {
throw std::bad_alloc();
}
} ~circle_buffer() {
clear(typename std::is_trivially_destructible<T>::type());
} size_t size() const noexcept {
if (m_endIdx < m_begIdx) {
return m_endIdx + m_bufSize - m_begIdx;
}
return m_endIdx - m_begIdx;
} bool empty() const noexcept {
return m_begIdx == m_endIdx;
} bool full() const noexcept {
return ((m_endIdx+) == m_begIdx) ||
(m_begIdx == && m_endIdx == getMaxIdx());
} // buffer最后插入一个值,这里会检查是否存在空间,如果不存在,则抛出异常
template <typename... Args>
void pushCheck(Args&&... args) {
if (full()) {
throw full_error("pushCheck invoked when buffer is full");
} push(std::forward<Args>(args)...);
} // buffer最后插入一个值,这里不做检查是否存在空间
template <typename... Args>
void push(Args&&... args) {
new (&m_buf[m_endIdx]) T(std::forward<Args>(args)...);
advanceIdx(m_endIdx);
} // buffer最前面取出一个值,这里会检查是否存在元素可以取出,如果不存在,则抛出异常
T popCheck() {
if (empty()) {
throw empty_error("popCheck invoked when buffer is empty");
} return pop();
} // buffer最前面取出一个值
T pop() {
auto val = std::move(m_buf[m_begIdx]);
clearOne(typename std::is_trivially_destructible<T>::type());
advanceIdx(m_begIdx);
return val;
} private:
// 将指示位置的序号前进一格
void advanceIdx(size_t& idx) noexcept {
if (idx == getMaxIdx()) {
idx = ;
} else {
++idx;
}
} // 非trivially析构函数类型
void clear(std::false_type) {
while (m_begIdx != m_endIdx) {
m_buf[m_begIdx].~T();
advanceIdx(m_begIdx);
}
std::free(m_buf);
} // trivially析构函数类型
void clear(std::true_type) {
std::free(m_buf);
} // 非trivially析构函数类型
void clearOne(std::false_type) {
m_buf[m_begIdx].~T();
} // trivially 析构函数类型
void clearOne(std::true_type) {
} size_t getMaxIdx() const noexcept {
return m_bufSize-;
} private:
size_type m_bufSize;
T* m_buf;
size_type m_begIdx;
size_type m_endIdx;
};
关于上面的环形数组,简单的单元测试代码如下,这里使用了catch2,如下代码需要放在.cpp文件中。
#define CATCH_CONFIG_MAIN
// This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"
#include "circle_buffer.h" TEST_CASE("circle buffer manipulation", "[circle_buffer]") {
circle_buffer<int> cb(); REQUIRE( cb.size() == );
REQUIRE( cb.empty() == true);
REQUIRE( cb.full() == false); cb.push();
cb.push(); REQUIRE( cb.size() == );
REQUIRE( cb.empty() == false );
REQUIRE( cb.full() == true ); auto dropFirst = cb.pop(); REQUIRE( dropFirst == );
REQUIRE( cb.size() == );
REQUIRE( cb.empty() == false );
REQUIRE( cb.full() == false ); cb.push(); REQUIRE( cb.size() == );
REQUIRE( cb.empty() == false );
REQUIRE( cb.full() == true); auto dropSecond = cb.pop(); REQUIRE( dropSecond == );
REQUIRE( cb.size() == );
REQUIRE( cb.empty() == false );
REQUIRE( cb.full() == false ); auto dropThird = cb.pop(); REQUIRE( dropThird == );
REQUIRE( cb.size() == );
REQUIRE( cb.empty() == true );
REQUIRE( cb.full() == false );
}
下面是基于环形数组实现的有最大长度限制的生产者消费者队列,注意一点,在使用下面队列时,编译选项要加上-std=c++11。
#include <condition_variable>
#include <chrono>
#include "circle_buffer.h" template <typename T>
class producer_consumer_queue {
public:
producer_consumer_queue(int maxSize): m_buffer(maxSize) { } // 处理数据线程
T readQueue() {
T data;
// 取出数据,然后处理数据
{
std::unique_lock<std::mutex> lock(m_queueMtx);
m_consumeCv.wait(lock, [this] { return !m_buffer.empty(); }); data = m_buffer.pop();
}
m_produceCv.notify_one(); return data;
} // 生产数据线程,返回值表示是否生产成功,如果超时就不会生产成功
template <typename Rep, typename Period, typename ...Args>
bool writeQueue(const std::chrono::duration<Rep, Period>& wait_time, Args&& ...args) {
// 预设一个消费者处理这个数据
{
std::unique_lock<std::mutex> lock(m_queueMtx);
auto success = m_produceCv.wait_for(lock, wait_time, [this] { return !m_buffer.full(); });
if (!success) {
return false;
}
m_buffer.push(std::forward<Args>(args)...);
}
m_consumeCv.notify_one();
return true;
} private:
// 用来缓存数据
circle_buffer<T> m_buffer;
// 用来保护数据
std::mutex m_queueMtx;
// 用来提醒当前可以消费
std::condition_variable m_consumeCv;
// 用来提醒当前可以生产
std::condition_variable m_produceCv;
};
以上就是这个队列的具体实现。之后,考虑写一些关于中间件的知识,可能会从grpc开始吧。
通过c++11的condition_variable实现的有最大缓存限制的队列的更多相关文章
- c+11 std::condition_variable and mutex
multiple threads synchronization primitive: 多线程同步语义 多线程的同步语义是多线程编程的核心,线程之间通过同步语义进行通信,实现并发.C++ JAVA 中 ...
- C++11 thread condition_variable mutex 综合使用
#include <mutex> #include <condition_variable> #include <chrono> #include <thre ...
- 【记录一个问题】ndk下使用c++11的condition_variable问题较多
1.存在通知丢失的情况:生产者线程通知196次,消费者线程收到190次,导致部分数据无法被处理. 2.cond.wait()方法后的加锁有问题,导致对空队列进行出队操作然后coredump.一直记得w ...
- 基于std::mutex std::lock_guard std::condition_variable 和std::async实现的简单同步队列
C++多线程编程中通常会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时造成资源争抢导致程序出现未定义的行为.通常的做法是在修改共享数据成员的时候进行加锁--mutex.在使用锁的时候通 ...
- C++11新特性之线程操作
C++11之前没有对并发编程提供语言级别的支持,这使得我们在编写可移植的并发程序时,存在诸多的不便.现在C++11增加了线程以及线程相关的类,很方便地支持了并发编程,使得编写的多线程程序的可移植性得到 ...
- 浅谈C++11中的多线程(三)
摘要 本篇文章围绕以下几个问题展开: 进程和线程的区别 何为并发?C++中如何解决并发问题?C++中多线程的基本操作 浅谈C++11中的多线程(一) - 唯有自己强大 - 博客园 (cnblogs.c ...
- 20191127 Spring Boot官方文档学习(4.11)
4.11.使用NoSQL技术 Spring Data提供了其他项目来帮助您访问各种NoSQL技术,包括: Redis MongoDB Neo4J Solr Elasticsearch Cassandr ...
- shared_ptr和多线程
前一篇文章写得实在太挫,重新来一篇. 多线程环境下生命周期的管理 多线程环境下,跨线程对象的生命周期管理会有什么挑战?我们拿生产者消费者模型来讨论这个问题. 实现一个简单的用于生产者消费者模型的队列 ...
- Web Server 和 HTTP 协议
https://toutiao.io/posts/xm2fr/preview 一直在找实习,有点什么东西直接就在evernote里面记了,也没时间来更新到这里.找实习真是个蛋疼的事,一直找的是困难模式 ...
随机推荐
- ZT 将sublime text的tab改为四个空格
打开Sublime Text3,选择菜单Preferences->Settings-User,打开用户配置文件(据本人理解,Settings-Default是不允许用户自己修改的~而Settin ...
- java后台常见问题
Java后台面试 常见问题 Nginx负载均衡 轮询.轮询是默认的,每一个请求按顺序逐一分配到不同的后端服务器,如果后端服务器down掉了,则能自动剔除 ip_hash.个请求按访问IP的hash结果 ...
- python 发送163邮件
可能还需要使用 邮箱第三方客户端的授权码. 网易163免费邮箱相关服务器信息 from email import encoders from email.header import Header fr ...
- 前端axios下载excel(二进制)
需求:通过后端接口下载excel文件,后端没有文件地址,返回二进制流文件 实现:axios(ajax类似) 主要代码: axios:设置返回数据格式为blob或者arraybuffer 如: var ...
- css3实现小程序的动画
<view class="biground" > <block wx:for="{{Namelist}}" wx:key=" ...
- C# 代码补全
cw + Tab + Tab 输出 Console.WriteLine(); try +Tab+Tab 输出 try catch代码块 foreach + Ta ...
- nginx uwsgi django 配置
用django框架,uwsgi服务器作为动态服务器,nginx作为静态资源服务器 配置uWSGI,在项目目录下创建uwsgi.ini文件: [uwsgi] #使用nginx连接时使用 socket=1 ...
- CMDB-实例
目录规划 bin ------> 启动文件 lib -------> 常见的库文件 src ------> 采集的核心代码 conf ----> 配置目录 log ------ ...
- CMDB-实现的几种方式
CMDB的用处:手机服务器的元信息 LINUX基础指令 查看IP地址 : ifconfig 查看主机名: hostname 查看CUP信息: cat /proc/cpuinfo 查看磁盘信息 : df ...
- LeetCode - Implement Magic Dictionary
Implement a magic directory with buildDict, and search methods. For the method buildDict, you'll be ...