文章目录

  • boost circular_buffer的特性及应用
    • boost circular_buffer的应用
      • circular_buffer实现的有界队列(消费生产者队列)
      • circular_buffer在音视频系统中的应用
        • 用于实现采集线程与编码线程间的队列
        • 用于实现解码线程与渲染线程间的队列

boost circular_buffer的特性及应用

boost库中的circular_bufer顾名思义是一个循环容器,官方文档的说明如下:

The circular_buffer is especially designed to provide fixed capacity storage. When its capacity is exhausted, newly inserted elements will cause elements to be overwritten, either at the beginning or end of the buffer (depending on what insert operation is used).

其capcity是固定的,不像标准容器中vector或list,他们的capcity是会根据策略动态增长的。当容量满了以后,插入一个元素时,会在容器的开头或结尾处删除一个元素。至于是头部还是尾部取决已加入的位置。

#include <iostream>
#include "boost/circular_buffer.hpp"int main()
{boost::circular_buffer<int> cb(3);cb.push_back(1);cb.push_back(2);cb.push_back(3);for (int i = 0; i < cb.size(); ++i){std::cout << cb[i] << " ";}std::cout << std::endl;//此时容量已满,下面新的push_back操作将在头部覆盖一个元素cb.push_back(4);for (int i = 0; i < cb.size(); ++i){std::cout << cb[i] << " ";}std::cout << std::endl;//下面的push_front操作将在尾部覆盖一个元素cb.push_front(5);for (int i = 0; i < cb.size(); ++i){std::cout << cb[i] << " ";}system("pause");
}

boost circular_buffer的应用

官方文档描述了几种circular_buffer的应用场景

  • Storage of the most recently received samples, overwriting the oldest as new samples arrive.
  • As an underlying container for a bounded buffer
  • A kind of cache storing a specified number of last inserted elements.
  • Efficient fixed capacity FIFO (First In, First Out)
  • Efficient fixed capacity LIFO (Last In, First Out) queue which removes the oldest (inserted as first) elements when full.

这里详细说明的是第二点应用场景。

circular_buffer实现的有界队列(消费生产者队列)

在多线程编程环境中通常会用到队列来分发数据或任务,circular_buffer非常适合来实现有界队列(消费生产者队列),其不但实现代码简单,效率也比用stl中的deque和list效率高。官方有一个例子,将circular_buffer与deque,list实现的有界队列进行了效率比较。
官方例子

下面是官方文档中基于circular_buffer实现的有界队列

template <class T>
class bounded_buffer {
public:typedef boost::circular_buffer<T> container_type;typedef typename container_type::size_type size_type;typedef typename container_type::value_type value_type;typedef typename boost::call_traits<value_type>::param_type param_type;explicit bounded_buffer(size_type capacity) : m_unread(0), m_container(capacity) {}void push_front(param_type item) {boost::unique_lock<boost::mutex> lock(m_mutex);m_not_full.wait(lock, boost::bind(&bounded_buffer<value_type>::is_not_full, this));m_container.push_front(item);++m_unread;lock.unlock();m_not_empty.notify_one();}void pop_back(value_type* pItem) {boost::unique_lock<boost::mutex> lock(m_mutex);m_not_empty.wait(lock, boost::bind(&bounded_buffer<value_type>::is_not_empty, this));*pItem = m_container[--m_unread];lock.unlock();m_not_full.notify_one();}private:bounded_buffer(const bounded_buffer&);              // Disabled copy constructorbounded_buffer& operator = (const bounded_buffer&); // Disabled assign operatorbool is_not_empty() const { return m_unread > 0; }bool is_not_full() const { return m_unread < m_container.capacity(); }size_type m_unread;container_type m_container;boost::mutex m_mutex;boost::condition_variable m_not_empty;boost::condition_variable m_not_full;
};

在官方的测试程序中,其效率比基于deque,list的实现高很多。注意上面pop_back的实现,取元素是通过下标去取并且在取出元素后也不用主动调用pop_back删除元素,这是因为circular_buffer在容量满的状态下,其内部实现会维持容量大小不变。反观基于deque,list的实现,如下pop_back方法的实现

void pop_back(value_type* pItem) {boost::unique_lock<boost::mutex> lock(m_mutex);m_not_empty.wait(lock, boost::bind(&bounded_buffer_deque_based<value_type>::is_not_empty, this));*pItem = m_container.back();m_container.pop_back();lock.unlock();m_not_full.notify_one();}

由于deque,list的容量是动态增长的,所以在pop_back中必须手动删除元素。这种与circular_buffer实现上的差别造成的效率差别,在元素是对象时特别明显,基于deque,list实现的队列pop_back方法中,在*pItem = m_container.back();处会构造一次对象,在m_container.pop_back();处会析构一次对象。比较例子可以看官方测试例子中对元素类型为std::string时的结果。

官方文档中有对该例子效率的一个描述

The bounded buffer::pop_back() method does not remove the item but the item is left in the circular_buffer which then replaces it with a new one (inserted by a producer) when the circular_buffer is full. This technique is more effective than removing the item explicitly by calling the circular_buffer::pop_back() method of the circular_buffer.

This claim is based on the assumption that an assignment (replacement) of a new item into an old one is more effective than a destruction (removal) of an old item and a consequent inplace construction (insertion) of a new item.

circular_buffer在音视频系统中的应用

用于实现采集线程与编码线程间的队列

在音视频系统(软编软解)中,如果有一个场景是采集出来的视频数据直接编码发送出去(一般的视频编码速度是大大低于采集图像的速度,特别是在编码高分辨率,大码率的情况下。)此时采集与编码为串行流程,那么极有可能出现视频图像延迟现象的。原因是编码影响了采集,造成采集的图像数据特别慢(一般的DirectShow采集和V4l2采集,需要向系统注册回调函数,系统会定时调用回调将数据传给应用,如果在回调中直接编码视频数据就会看到图像延迟的情况)。此时需要实现采集和编码异步进行,那么可用通过队列来实现(采集线程与编码线程通过队列来交互数据),因为编码线程是肯定慢于采集线程的,此时使用消费生产者队列是不适合的。这种队列应具有如下特点:

  1. 长度固定并且不能过长,否则依然会出现延迟问题。
  2. 在该队列中数据满时,必须丢掉最老的视频图像数据。

这种队列非常适合用circular_buffer来实现,实现代码如下:

template <class T>
class DataQueue:public boost::noncopyable
{public:typedef boost::circular_buffer<T> BufferType;typedef typename BufferType::size_type size_type;typedef typename BufferType::value_type value_type;explicit DataQeque(size_type size) :m_Qeque(size){}void Put(const value_type &data){{std::lock_guard<std::mutex> lock(m_mutex);m_Qeque.push_back(data);}m_cndNotEmpty.notify_one();}void Get(value_type &data){std::unique_lock<std::mutex> lock(m_mutex);while (m_Qeque.empty()){m_cndNotEmpty.wait(lock);}data = m_Qeque.front();}private:BufferType m_Qeque;std::mutex m_mutex;std::condition_variable m_cndNotEmpty;};

如果在编码线程慢于采集线程可以确定的情况下(绝大多数情况即使不是编码高清码流,编码线程效率也是小于采集线程的),m_cndNotEmpty这个条件变量可以不用要。

使用这样的队列有一个“副作用”,会出现跳帧的情况,这些因为老的视频图像被丢弃造成的,有一种情况在编码线程效率大大低于采集线程,如果队列长度设置的过小,此时会出现严重的跳帧,将队列大小加大可以缓解频繁的跳帧问题。

用于实现解码线程与渲染线程间的队列

这个场景其实跟上面描述的场景一样,渲染线程(比如用opengl渲染)慢于解码线程,同样会出现上述情况,此时用上述队列同样可以应用于该场景。

以上。

资料:

http://www.boost.org/doc/libs/1_66_0/doc/html/circular_buffer.html
http://www.boost.org/doc/libs/1_66_0/libs/circular_buffer/test/bounded_buffer_comparison.cpp

boost circular_buffer的特性及应用相关推荐

  1. 【C++】31. Boost::circular_buffer——循环缓冲区

    一.概述 Boost.Circular_buffer维护了一块连续内存块作为缓存区,当缓存区内的数据存满时,继续存入数据就覆盖掉旧的数据. 它是一个与STL兼容的容器,类似于 std::list或st ...

  2. 循环(环形)缓冲区之Boost::circular_buffer

    1. 简介 虽然STL中有queue和deque,但是他们是无限扩展大小的,如果想限定一个定量缓冲,就必须不停的pop操作,而且queue没有随机访问的操作.如果想要维护一个定长缓冲区,我们可以考虑使 ...

  3. 【C++】Boost::circular_buffer——循环缓冲区

    参考:Boost::circular_buffer--循环缓冲区 一.概述 Boost.Circular_buffer维护了一块连续内存块作为缓存区,当缓存区内的数据存满时,继续存入数据就覆盖掉旧的数 ...

  4. Boost: 检查underlying_type特性是否有效的测试程序

    boost::core模块检查underlying_type特性是否有效 实现功能 C++实现代码 实现功能 boost::core模块检查underlying_type特性是否有效 C++实现代码 ...

  5. boost circular_buffer

    circular_buffer是一块内存区域,当这块区塞满数据的时候,新数据会覆盖掉旧的数据. 类似于std::list 或者std::deque.支持随机访问,在头尾的插入和删除操作的耗时为常数,并 ...

  6. 如何检查计算机上安装的DirectX版本?

    这是显示使用DirectX诊断工具检查计算机上安装的Microsoft DirectX版本的指南. 1.单击" 开始 "或" Windows按钮 ",然后单击& ...

  7. Boost库之circular_buffer

    Boost库之circular_buffer 原文:http://blog.csdn.net/byxdaz/article/details/71631470 Boost.Circular_buffer ...

  8. Boost:circular_buffer作为边界缓冲区的基础容器

    Boost:circular_buffer作为边界缓冲区的基础容器 实现功能 C++实现代码 实现功能 circular_buffer作为边界缓冲区的基础容器 C++实现代码 #include < ...

  9. Boost:循环缓冲区总和的测试程序

    Boost:循环缓冲区总和的测试程序 实现功能 C++实现代码 实现功能 循环缓冲区总和的测试程序 C++实现代码 #include <boost/circular_buffer.hpp> ...

最新文章

  1. PyTorch 笔记(20)— torchvision 的 datasets、transforms 数据预览和加载、模型搭建(torch.nn.Conv2d/MaxPool2d/Dropout)
  2. Oracle常用傻瓜问题1000问
  3. 网络编程 UDP通信的过程 TCP通信过程 多线程文件上传
  4. linux常用svn命令
  5. 为input输入框添加圆角并去除阴影
  6. HBase 基本Java API
  7. Extjs4开发中的一些问题
  8. 安装solc模块4.25版本
  9. java 13个核心技术3
  10. MySQL高阶面试题
  11. jQuery 进度条实现
  12. c++ 位运算 和 掩码
  13. docx行间距怎么设置_word2017如何设置行间距.docx
  14. 《介绍几个常见常用的字符函数》(包括isdigit,isupper,islower,isalpha,isalnum,toupper,tolower)
  15. Vmware报错“该虚拟机似乎正在使用中”获取该虚拟机所有权失败的解决
  16. CentOS6 双线双ip服务器路由设置方法
  17. vin端口是什么意思_5G新在哪儿(6)?-天线端口的故事
  18. 电脑突然找不到wifi 的解决方法
  19. Matlab论文插图绘制模板第28期—柱状图(带误差棒errorbar)
  20. 日常编程笔记 | 2022.10.1 | 归并排序_一无序列

热门文章

  1. 使用代理抓取反爬微信文章
  2. 【我的渲染技术进阶之旅】关于C++轻量级界面开发框架Dear ImGui介绍
  3. STM32与OLED显示姓名学号
  4. 保研被鸽,去了自己不理想的学校怎么办?
  5. slam十四讲-ch6-非线性优化(包含手写高斯牛顿、使用g2o库、使用ceres库三种方法的源码详细注释)
  6. 魔兽争霸3在win10中调节亮度的办法
  7. 魅蓝note2解锁bootloader教程
  8. 十六.Elasticsearch Adjacency Matrix Aggregation
  9. Android界面编程之简单的图片浏览器
  10. Bean with name ‘‘ has been injected into other beans [] in its raw version as part of a circular ref