21xrx.com
2024-11-22 07:11:14 Friday
登录
文章检索 我的文章 写文章
C++多线程队列(Queue)
2023-07-05 12:22:09 深夜i     --     --
C++ 多线程 队列 线程安全 生产者消费者模型

在多线程编程中,队列是一种常用的数据结构。C++中标准库中自带了队列(queue)容器,但是该容器是线程不安全的。这意味着如果多个线程同时访问队列,可能会导致数据竞争和错误结果。为了解决这个问题,我们需要使用线程安全的队列(thread-safe queue)来提供安全的数据共享。

C++中实现线程安全队列的方法有很多,最常见的方法是使用互斥锁(mutex)和条件变量(condition variable)。在队列的Push和Pop操作中,我们使用互斥锁来保证各线程的互斥性,条件变量来通知线程有新的数据可以处理。具体地,队列中的Push操作中,首先获取互斥锁,然后插入元素,最后通知条件变量,唤醒等待中的线程;而队列中的Pop操作中,首先获取互斥锁,然后弹出元素,最后判断队列是否为空,如果为空,则等待条件变量的通知。

这里是使用互斥锁和条件变量实现的一个线程安全队列的示例:


template<typename T>

class thread_safe_queue{

private:

 mutable std::mutex mut;

 std::queue<T> data_queue;

 std::condition_variable data_cond;

public:

 thread_safe_queue(){}

 void push(T new_value){

  std::lock_guard<std::mutex> lk(mut); // 获取互斥锁

  data_queue.push(std::move(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=std::move(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>(std::move(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=std::move(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>(std::move(data_queue.front())));

  data_queue.pop();

  return res;

 }

 bool empty() const{

  std::lock_guard<std::mutex> lk(mut);

  return data_queue.empty();

 }

};

该实现提供了一些不同类型的Pop操作:wait_and_pop会等待直到队列中出现新的数据;try_pop会立即返回,如果队列为空,则返回false。同时,还提供了empty操作用来检查队列是否为空。

当多个线程同时访问该队列时,数据会被自动保护,从而避免了数据竞争和错误。

在使用时,需要注意实现的类型是泛型的,即可以适用于任何类型的数据,例如:


thread_safe_queue<int> my_queue;

my_queue.push(42);

int value;

my_queue.wait_and_pop(value);

std::shared_ptr<int> ptr=my_queue.try_pop();

总之,线程安全队列是多线程编程中非常重要的一种数据结构。使用C++中的互斥锁和条件变量,可以很容易地实现线程安全队列,并且可以适用于任何类型的数据。为了保证程序的正确性和效率,在设计多线程程序时,我们应该优先考虑线程安全队列的使用。

  
  
下一篇: C99是C++吗?

评论区

{{item['qq_nickname']}}
()
回复
回复