一个有锁线程安全的队列实现 | Blurred code

一个有锁线程安全的队列实现

2020/02/03

Updated:2020/02/03

Categories: cpp

最近在学习pthread的过程中,也算是重温了多线程编程的一些知识。关于单生产者单消费者的模式,最佳实践应该是circle buffer,可以无锁操作,可是STL里没有提供该容器。github上有一个高性能的readwritequeue1,实现了lock-free的queue,benchmark看了一下性能还可以,API接口也很好看。Boost库的lockfree里也有一个queue,不过没有用过。

在实际中,如果在queue上不是瓶颈,想自己封一下的话,也就几十行就能把std::queue封成线程安全的,主要要用到C++11里的条件变量和互斥锁。 benchmark下,大概比刚刚提到的lockfree的慢50倍吧:)。

#pragma once
#include <condition_variable>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>

template <typename T> class safe_queue {
public:
  safe_queue() { queue_ptr_ = std::make_unique<std::queue<T>>(); }
  ~safe_queue() {}
  safe_queue(const safe_queue &other) = delete;
  safe_queue(safe_queue &&other) = delete;
  safe_queue &operator=(const safe_queue &other) = delete;

  T pop() {
    std::unique_lock<std::mutex> guard(mutex_);
    while (queue_ptr_->empty()) {
      cond_.wait(guard);
    }
    T first = queue_ptr_->front(); // reference?
    queue_ptr_->pop();
    return first;
  }

  void push(const T &item) {
    {
      std::lock_guard<std::mutex> guard(mutex_);
      queue_ptr_->push(item);
    }
    cond_.notify_one();
  }

  void push(T &&item) {
    {
      std::lock_guard<std::mutex> guard(mutex_);
      queue_ptr_->push(std::move(item));
    }
    cond_.notify_one();
  }

  bool empty() {
    std::lock_guard<std::mutex> guard(mutex_);
    return queue_ptr_->empty();
  }

  bool empty() const { return queue_ptr_->empty(); }

private:
  std::unique_ptr<std::queue<T, std::deque<T>>> queue_ptr_; // deque
  std::mutex mutex_;
  std::condition_variable cond_;
};

  1. https://github.com/cameron314/readerwriterqueue ↩︎