21xrx.com
2025-03-14 11:55:22 Friday
文章检索 我的文章 写文章
C++队列queue多线程实现
2023-07-05 04:29:55 深夜i     13     0
C++ 队列(queue) 多线程(multithreading) 实现(implementation)

队列是计算机科学中经典的数据结构之一,它允许我们按照先进先出(FIFO)的顺序存储元素,并在队列尾部插入元素,在队列头部删除元素。在C++中,实现队列最常见的方式是使用STL库中的队列(queue)数据结构。

单线程环境下,队列的实现是非常简单的,但在多线程环境下,队列的实现就变得更加复杂。在多线程环境下,为了保证线程安全,需要对队列进行一些额外的操作。

使用C++队列queue实现多线程的方式有很多种,下面介绍其中两种方法:

1. 互斥锁和条件变量

这是最常见的一种方法,即使用互斥锁来保证线程的安全性,在队列中插入和删除元素的过程中加锁,这样就保证了同时只有一个线程可以访问队列。当队列为空时,等待条件变量通知,当队列不为空时,唤醒这些线程。

示例代码:

#include<queue>
#include<mutex>
#include<condition_variable>
using namespace std;
template<typename T>
class ThreadsafeQueue {
private:
  queue<T> q;
  mutex mtx;
  condition_variable cv;
public:
  ThreadsafeQueue() = default;
  void push(T t) {
    lock_guard<mutex> lock(mtx);
    q.push(t);
    cv.notify_one();
  }
  bool try_pop(T& t) {
    lock_guard<mutex> lock(mtx);
    if (q.empty())
      return false;
    
    t = q.front();
    q.pop();
    return true;
  }
  void wait_and_pop(T& t) {
    unique_lock<mutex> lock(mtx);
    cv.wait(lock, [this] {return !q.empty(); });
    t = q.front();
    q.pop();
  }
};

2. 无锁队列

面对高并发的情况,使用锁会使性能大大降低,一种更好的选择是使用无锁队列,该队列可以保证线程安全。当一个线程想要入队或出队时,该线程就会比较并交换数据结构的元素。

示例代码:

#include<atomic>
#include<pthread.h>
using namespace std;
template<class T>
class lock_free_queue
{
private:
  struct node
  {
    T data;
    node* next;
  };
  atomic<node*> head;
  atomic<node*> tail;
public:
  lock_free_queue()
  {
    node* null_node = new node;
    null_node->data = 0;
    null_node->next = nullptr;
    head.store(null_node, memory_order_relaxed);
    tail.store(head.load(memory_order_relaxed), memory_order_relaxed);
  }
  ~lock_free_queue()
  {
    node* old_head;
    while (head.load(memory_order_relaxed) != nullptr)
    {
      old_head = head.load(memory_order_relaxed);
      head.store(old_head->next, memory_order_relaxed);
      delete old_head;
    }
  }
  void push(T value)
  {
    node* new_node = new node;
    new_node->data = value;
    new_node->next = nullptr;
    node* prev_tail = tail.load(memory_order_relaxed);
    node* update_tail = prev_tail;
    while (true)
    {
      node* null_node = nullptr;
      if (prev_tail == tail.load(memory_order_relaxed))
      {
        if (prev_tail->next == nullptr)
        {
          if (atomic_compare_exchange_weak_explicit(&prev_tail->next, &null_node, new_node, memory_order_release, memory_order_relaxed))
          
            break;
          
        }
        else
        {
          atomic_compare_exchange_weak_explicit(&tail, &prev_tail, prev_tail->next, memory_order_release, memory_order_relaxed);
        }
      }
      prev_tail = tail.load(memory_order_relaxed);
    }
    atomic_compare_exchange_weak_explicit(&tail, &update_tail, new_node, memory_order_release, memory_order_relaxed);
  }
  bool try_pop(T& value)
  {
    while (true)
    {
      node* const current_head = head.load(memory_order_relaxed);
      node* const current_tail = tail.load(memory_order_relaxed);
      node* const first_node = current_head->next;
      if (current_head == head.load(memory_order_acquire))
      {
        if (current_head == current_tail)
        {
          if (first_node == nullptr)
          
            return false;
          
          atomic_compare_exchange_weak_explicit(&tail, &current_tail, first_node, memory_order_release, memory_order_relaxed);
        }
        else
        {
          value = first_node->data;
          if (atomic_compare_exchange_weak_explicit(&head, &current_head, first_node, memory_order_release, memory_order_relaxed))
          
            delete current_head;
            break;
          
        }
      }
    }
    return true;
  }
};

总之,在使用队列queue实现多线程时,我们应该考虑线程安全性和高效性,根据实际情况选择合适的实现方式,从而保证程序的稳定和高效运行。

  
  

评论区

    相似文章
请求出错了