最近在学习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_;
};