C++11:基于std::queue和std::mutex构建一个线程安全的队列

C++中的模板std::queue提供了一个队列容器,但这个容器并不是线程安全的,如果在多线程环境下使用队列,它是不能直接拿来用的。
基于它做一个线程安全的队列也并不复杂。基本的原理就是用std::mutext信号量对std::queue进行访问控制,以保证任何一个线程都是独占式访问,下面是完整的代码。

  1. /*
  2. * threadsafe_queue.h
  3. *
  4. * Created on: 2016年7月26日
  5. * Author: guyadong
  6. */
  7.  
  8. #ifndef COMMON_SOURCE_CPP_THREADSAFE_QUEUE_H_
  9. #define COMMON_SOURCE_CPP_THREADSAFE_QUEUE_H_
  10. #include <queue>
  11. #include <mutex>
  12. #include <condition_variable>
  13. #include <initializer_list>
  14. namespace gdface {
  15. inline namespace mt{
  16. /*
  17. * 线程安全队列
  18. * T为队列元素类型
  19. * 因为有std::mutex和std::condition_variable类成员,所以此类不支持复制构造函数也不支持赋值操作符(=)
  20. * */
  21. template<typename T>
  22. class threadsafe_queue{
  23. private:
  24. // data_queue访问信号量
  25. mutable std::mutex mut;
  26. mutable std::condition_variable data_cond;
  27. using queue_type = std::queue<T>;
  28. queue_type data_queue;
  29. public:
  30. using value_type= typename queue_type::value_type;
  31. using container_type = typename queue_type::container_type;
  32. threadsafe_queue()=default;
  33. threadsafe_queue(const threadsafe_queue&)=delete;
  34. threadsafe_queue& operator=(const threadsafe_queue&)=delete;
  35. /*
  36. * 使用迭代器为参数的构造函数,适用所有容器对象
  37. * */
  38. template<typename _InputIterator>
  39. threadsafe_queue(_InputIterator first, _InputIterator last){
  40. for(auto itor=first;itor!=last;++itor){
  41. data_queue.push(*itor);
  42. }
  43. }
  44. explicit threadsafe_queue(const container_type &c):data_queue(c){}
  45. /*
  46. * 使用初始化列表为参数的构造函数
  47. * */
  48. threadsafe_queue(std::initializer_list<value_type> list):threadsafe_queue(list.begin(),list.end()){
  49. }
  50. /*
  51. * 将元素加入队列
  52. * */
  53. void push(const value_type &new_value){
  54. std::lock_guard<std::mutex>lk(mut);
  55. data_queue.push(std::move(new_value));
  56. data_cond.notify_one();
  57. }
  58. /*
  59. * 从队列中弹出一个元素,如果队列为空就阻塞
  60. * */
  61. value_type wait_and_pop(){
  62. std::unique_lock<std::mutex>lk(mut);
  63. data_cond.wait(lk,[this]{return !this->data_queue.empty();});
  64. auto value=std::move(data_queue.front());
  65. data_queue.pop();
  66. return value;
  67. }
  68. /*
  69. * 从队列中弹出一个元素,如果队列为空返回false
  70. * */
  71. bool try_pop(value_type& value){
  72. std::lock_guard<std::mutex>lk(mut);
  73. if(data_queue.empty())
  74. return false;
  75. value=std::move(data_queue.front());
  76. data_queue.pop();
  77. return true;
  78. }
  79. /*
  80. * 返回队列是否为空
  81. * */
  82. auto empty() const->decltype(data_queue.empty()) {
  83. std::lock_guard<std::mutex>lk(mut);
  84. return data_queue.empty();
  85. }
  86. /*
  87. * 返回队列中元素数个
  88. * */
  89. auto size() const->decltype(data_queue.size()){
  90. std::lock_guard<std::mutex>lk(mut);
  91. return data_queue.size();
  92. }
  93. }; /* threadsafe_queue */
  94. }/* namespace mt */
  95. }/* namespace gdface */
  96. #endif /* COMMON_SOURCE_CPP_THREADSAFE_QUEUE_H_ */

这里只实现了阻塞式的pop函数wait_and_pop,你也可以根据自己的需要对代码进行适当的改造,以符合自己的需求。 
(C++11风格代码,在VS2015和gcc5.2.0下编译通过)

  1. 因为有std::mutexstd::condition_variable类成员,所以此类不支持复制构造函数也不支持赋值操作符(=)

C++11:基于std::queue和std::mutex构建一个线程安全的队列的更多相关文章

  1. std::atomic和std::mutex区别

    ​ ​std::atomic介绍​ ​模板类std::atomic是C++11提供的原子操作类型,头文件 #include<atomic>.​在多线程调用下,利用std::atomic可实 ...

  2. 构建一个基于事件分发驱动的EventLoop线程模型

    在之前的文章中我们详细介绍过Netty中的NioEventLoop,NioEventLoop从本质上讲是一个事件循环执行器,每个NioEventLoop都会绑定一个对应的线程通过一个for(;;)循环 ...

  3. 基于std::mutex std::lock_guard std::condition_variable 和std::async实现的简单同步队列

    C++多线程编程中通常会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时造成资源争抢导致程序出现未定义的行为.通常的做法是在修改共享数据成员的时候进行加锁--mutex.在使用锁的时候通 ...

  4. std::vector与std::list效能对比(基于c++11)

    测试对象类型不同,数量级不同时,表现具有差异: 测试数据对象为std::function时: test: times(1000)vector push_back time 469 usvector e ...

  5. C++11 std::unique_lock与std::lock_guard区别及多线程应用实例

    C++多线程编程中通常会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时造成资源争抢导致程序出现未定义的行为.通常的做法是在修改共享数据成员的时候进行加锁--mutex.在使用锁的时候通 ...

  6. C++11并发——多线程条件变量std::condition_variable(四)

    https://www.jianshu.com/p/a31d4fb5594f https://blog.csdn.net/y396397735/article/details/81272752 htt ...

  7. C++ 11 多线程下std::unique_lock与std::lock_guard的区别和用法

    这里主要介绍std::unique_lock与std::lock_guard的区别用法 先说简单的 一.std::lock_guard的用法 std::lock_guard其实就是简单的RAII封装, ...

  8. c++11特性与cocos2d-x 3.0之std::bind与std::function

    昨天同事让帮忙写一小功能,才发现cocos2d-x 3.0 和 cocos2d-x 3.0rc0 差别还是相当大的. 发现Label这一个控件,3.0就比rc0版本多了一个创建函数,更为关键的是3.0 ...

  9. C++ std::queue

    std::queue template <class T, class Container = deque<T> > class queue; FIFO queue queue ...

随机推荐

  1. CI框架扩展系统类库

    CI框架不支持像yii2框架那样,可以直接在controllers下创建CommonController并继承父类,那么我们想要做登录控制或权限控制时,直接在父类控制器操作是不合理的. 这时比较方便的 ...

  2. [CAN].CAN总线详解

    转自:https://blog.csdn.net/cheatscat/article/details/82886889 CAN(Controller Area Network)总线协议是由 BOSCH ...

  3. 新建本地用户连接vsftp出现530 Login incorrect

    新建的用户的方式 [root@centos2 /var/ftp]# useradd -s /sbin/nologin user1 出错原因: /etc/pam.d/vsftp文件作了限制 [root@ ...

  4. Eclipse搭建maven web项目

    最近在做做一个小实验,搭建ssm框架,要求使用maven来统一管理jar包,接下来就看如何建立maven项目,首先必须有要有相应的开发环境:JDK和maven,以及配置tomcat. 开发环境搭建可以 ...

  5. 转 OJDBC驱动版本区别 [ojdbc14.jar,ojdbc5.jar跟ojdbc6.jar的区别]

    OJDBC版本区别 [ojdbc14.jar,ojdbc5.jar和ojdbc6.jar的区别] 在使用Oracle JDBC驱动时,有些问题你是不是通过替换不同版本的Oracle  JDBC驱动来解 ...

  6. java接口的成员变量的修饰符

    前言:c++学的java都忘记了不少 interface(接口)可将其想象为一个"纯"抽象类.它允许创建者规定一个类的基本形式:方法名.自变量列表以及返回类型,但不实现方法主体 接 ...

  7. [Flutter + Firebase] Enable Firebase for Flutter

    Anroid Firebase Project setup: 1. In firebase console, cerate a Android app setup you can find in co ...

  8. [NPM + React] Prepare a Custom React Hook to be Published as an npm Package

    Before we publish our package, we want to make sure everything is set up correctly. We’ll cover vers ...

  9. C++ socket bind() 函数绑定错误

    VS2015编译错误: errorCxxxx: 'initializing' : cannot convert from 'std::_Bind<false,void,SOCKET&,s ...

  10. B/S开发——文件夹的上传和下载

    本人在2010年时使用swfupload为核心进行文件的批量上传的解决方案.见文章:WEB版一次选择多个文件进行批量上传(swfupload)的解决方案. 本人在2013年时使用plupload为核心 ...