c++11 多线程编程——如何实现线程安全队列

线程安全队列的接口文件如下:

#include <memory>
template<typename T>
class threadsafe_queue {
 public:
  threadsafe_queue();
  threadsafe_queue(const threadsafe_queue&);
  threadsafe_queue& operator=(const threadsafe_queue&) = delete;

  void push(T new_value);

  bool try_pop(T& value);
  std::shared_ptr<T> try_pop();

  void wait_and_pop(T& value);
  std::shared_ptr<T> wait_and_pop();

  bool empty() const;
};

push函数

push()函数实现向队列添加数据的功能。添加数据后,使用std::condition_variable的notify_one通知取数据时被阻塞的线程。

void push(T tValue) {
  std::shared_ptr<T> data(std::make_shared<T>(std::move(tValue)));
  std::lock_guard<std::mutex> lk(mut);
  data_queue.push(data);
  data_con.notify_one();
}

wait_and_pop函数

wait_and_pop()函数实现从队列取数据的功能,当队列为空时,线程被挂起,等待有数据时被唤醒。

注意,这两个函数中没有使用std::lock_guard,而是使用std::unique_lock,这是为什么呢?

这是因为std::condition_variable的wait函数会首先检测条件data_queue.empty()是否满足,如果队列为空,wait函数会释放mutex,并被挂起;当有新的数据进入队列,std::condition_variable的wait函数会被唤醒,重新尝试获取mutex,然后检测队列是否为空,如果队列非空,则继续向下执行。由于函数的执行过程存在锁的释放和重新获取,所以没有使用std::lock_guard,而是选择了std::unique_lock。

void wait_and_pop(T& value) {
  std::unique_lock<std::mutex> lk(mut);
  data_cond.wait(lk,[this]{return !data_queue.empty();});
  value=data_queue.front();
  data_queue.pop();
}

std::shared_ptr<T> wait_and_pop() {
  std::unique_lock<std::mutex> lk(mut);
  data_cond.wait(lk,[this]{return !data_queue.empty();});
  std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
  data_queue.pop();
  return res;
}

try_pop函数

try_pop函数提供非阻塞调用下的弹出队列(queue)的功能。弹出成功返回true或者非空shared_ptr,失败则返回false或者nullptr。

bool try_pop(T& value) {
  std::lock_guard<std::mutex> lk(mut);
  if(data_queue.empty()) {
    return false;
  }
  value = data_queue.front();
  data_queue.pop();

  return true;
}

std::shared_ptr<T> try_pop() {
  std::lock_guard<std::mutex> lk(mut);
  if(data_queue.empty()) {
    return std::shared_ptr<T>();
  }
  std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
  data_queue.pop();
  return res;
}

empty函数

bool empty() const {
  std::lock_guard<std::mutex> lk(mut);
  return data_queue.empty();
}

这里注意,empty()是const类型的成员函数,表明它声明自己并不改变任何成员变量,但是mutex lock是一个mutating opertation,所以必须要将mut声明为mutable类型(mutable std::mutex mut)。

完整代码如下:

#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>

template<typename T>
class threadsafe_queue {
 private:
   mutable std::mutex mut;
   std::queue<T> data_queue;
   std::condition_variable data_cond;
 public:
   threadsafe_queue(){}
   threadsafe_queue(threadsafe_queue const& other) {
     std::lock_guard<std::mutex> lk(other.mut);
     data_queue=other.data_queue;
   }

   void push(T new_value) {
     std::lock_guard<std::mutex> lk(mut);
     data_queue.push(new_value);
     data_cond.notify_one();
   }

   void wait_and_pop(T& value) {
     std::unique_lock<std::mutex> lk(mut);
     data_cond.wait(lk,[this]{return !data_queue.empty();});
     value=data_queue.front();
     data_queue.pop();
   }

   std::shared_ptr<T> wait_and_pop() {
     std::unique_lock<std::mutex> lk(mut);
     data_cond.wait(lk,[this]{return !data_queue.empty();});
     std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
     data_queue.pop();
     return res;
   }

   bool try_pop(T& value) {
     std::lock_guard<std::mutex> lk(mut);
     if(data_queue.empty())
       return false;
     value=data_queue.front();
     data_queue.pop();
     return true;
   }

   std::shared_ptr<T> try_pop() {
     std::lock_guard<std::mutex> lk(mut);
     if(data_queue.empty())
       return std::shared_ptr<T>();
     std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
     data_queue.pop();
     return res;
   }

   bool empty() const {
     std::lock_guard<std::mutex> lk(mut);
     return data_queue.empty();
   }
};

以上就是c++ 如何实现线程安全队列的详细内容,更多关于c++ 线程安全队列的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++基于消息队列的多线程实现示例代码

    前言 实现消息队列的关键因素是考量不同线程访问消息队列的同步问题.本实现涉及到几个知识点 std::lock_guard 介绍 std::lock_gurad 是 C++11 中定义的模板类.定义如下: template <class Mutex> class lock_guard; lock_guard 对象通常用于管理某个锁(Lock)对象,因此与 Mutex RAII 相关,方便线程对互斥量上锁,即在某个 lock_guard 对象的声明周期内,它所管理的锁对象会一直保持上锁状态:而 l

  • C++11并发编程:多线程std::thread

    一:概述 C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改.现在在C++11中只需使用语言层面的thread可以解决这个问题. 所需头文件<thread> 二:构造函数 1.默认构造函数 thread() noexcept 一个空的std::thread执行对象 2.初始化构造函数 template<class Fn, class... Args> explicit th

  • c++11多线程编程之std::async的介绍与实例

    本节讨论下在C++11中怎样使用std::async来执行异步task. C++11中引入了std::async 什么是std::async std::async()是一个接受回调(函数或函数对象)作为参数的函数模板,并有可能异步执行它们. template<class Fn, class... Args> future<typename result_of<Fn(Args...)>::type> async(launch policy, Fn&& fn

  • c++多线程之死锁的发生的情况解析(包含两个归纳,6个示例)

    一.死锁会在什么情况发生 1.假设有如下代码 mutex; //代表一个全局互斥对象 void A() { mutex.lock(); //这里操作共享数据 B(); //这里调用B方法 mutex.unlock(); return; } void B() { mutex.lock(); //这里操作共享数据 mutex.unlock(); return; } 此时会由于在A.B方法中相互等待unlock而导致死锁. 2.假设有如何代码 mutex; //代表一个全局互斥对象 void A()

  • C++11中多线程编程-std::async的深入讲解

    前言 C++11中提供了异步线程接口std::async,std::async是异步编程的高级封装,相对于直接使用std::thread,std::async的优势在于: 1.std::async会自动创建线程去调用线程函数,相对于低层次的std::thread,使用起来非常方便: 2.std::async返回std::future对象,通过返回的std::future对象我们可以非常方便的获取到线程函数的返回结果: 3.std::async提供了线程的创建策略,可以指定同步或者异步的方式去创建

  • C++多线程中的锁和条件变量使用教程

    在做多线程编程时,有两个场景我们都会遇到: 多线程访问共享资源,需要用到锁: 多线程间的状态同步,这个可用的机制很多,条件变量是广泛使用的一种. 今天我用一个简单的例子来给大家介绍下锁和条件变量的使用. 代码使用C++11 示例代码 #include <iostream> #include <mutex> #include <thread> #include <condition_variable> std::mutex g_mutex; // 用到的全局锁

  • Windows下使用Dev-C++开发基于pthread.h的多线程程序实例

    一.下载Windows版本的pthread 目前最新版本是:pthreads-w32-2-9-1-release.zip. 二.解压pthread到指定目录 我选择的目录是:E:\DEV-CPP\Pthread 完成后,该目录会多出三个文件夹:Pre-built.2,pthreads.2,QueueUserAPCEx. 三.配置Dev-C++编译选项 1)点击"工具"→"编译选项"→"目录"→"c++包含文件",浏览到刚才解压

  • linux下的C\C++多进程多线程编程实例详解

    linux下的C\C++多进程多线程编程实例详解 1.多进程编程 #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main() { pid_t child_pid; /* 创建一个子进程 */ child_pid = fork(); if(child_pid == 0) { printf("child pid\n"); exit(0); } else { print

  • C++多线程实现电子词典

    本文实例为大家分享了C++多线程实现电子词典的具体代码,供大家参考,具体内容如下 // Dictionary.cpp : 定义控制台应用程序的入口点. //vs2013编译 //字典文件:https://pan.baidu.com/s/1YHtwptaq_V8j034U9_J96A #include "stdafx.h" #include <string> #include <vector> #include <iostream> #include

  • c++11新特性多线程操作实战

    c++11多线程操作 线程 thread int main() { thread t1(Test1); t1.join(); thread t2(Test2); t2.join(); thread t3 = t1; thread t4(t1); thread t5 = std::move(t1); thread t6(std::move(t1)); return 0; } t3,t4创建失败,因为thread的拷贝构造和赋值运算符重载的原型是: thread(const thread&) = d

  • C++多线程获取返回值方法详解

    在许多时候,我们会有这样的需求--即我们想要得到线程返回的值.但是在C++11 多线程中我们注意到,std::thread对象会忽略顶层函数的返回值. 那问题来了,我们要怎么获得线程的返回值呢? 我们通过一个例子来说明如何实现这个需求.用多个线程计算(a+b)/ (x+y) 的值 有两种方法,分别是 1. 传统的方法:在线程间共享指针 #include<iostream> #include<thread> #include<mutex> #include<atom

  • C++多线程编程简单实例

    C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程的程序,下面就此简单的讲一下: 创建线程的函数 复制代码 代码如下: HANDLE CreateThread(     LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD     SIZE_T dwStackSize,                       // initial stack size     LPTHREAD_START_

随机推荐