SafeQueue类继承与信号量mutex(用于加锁),nonocopyable
定义如下:
template <typename T> struct SafeQueue : private std::mutex, private noncopyable { static const int wait_infinite = std::numeric_limits<int>::max(); SafeQueue(size_t capacity = 0) : capacity_(capacity), exit_(false) {} bool push(T&& v) T pop_wait(int waitMs = wait_infinite); bool pop_wait(T* v, int waitMs = wait_infinite); size_t size(); void exit(); bool exited() { return exit_; } private: std::list<T> items_; std::condition_variable ready_; size_t capacity_; std::atomic<bool> exit_; void wait_ready(std::unique_lock<std::mutex>& lk, int waitMs); };
该类可以安全的添加和删除任务,类内部使用容器list来存储具体的任务,具有退出状态:exit_,取出任务时可以设定超时时间。
其中Task的定义为:typedef std::function<void()> Task; Task为返回值为空的函数对象
SafeQueue的具体实现如下:
template <typename T> size_t SafeQueue<T>::size() { std::lock_guard(std::mutex) lk(*this); return items_.size(); } template <typename T> void SafeQueue<T>::exit() { exit_ = true; std::lock_guard<std::mutex> lk(*this); ready_.notify_all(); } template <typename T> bool SafeQueue<T>::push(T&& v) { std::lock_guard<std::mutex> lk(*this); if (exit_ || (capacity_ && items_.size() >= capacity_)) { return false; } items_.push_back(std::move(v)); ready_.notify_one(); return true; } template <typename T> void SafeQueue<T>::wait_ready(std::unique_lock<std::mutex>& lk, int waitMs) { if (exit_ || !items_.empty()) { return; } if (waitMs == wait_infinite) { ready_.wait(lk, [this] { return exit_ || !items_.empty(); }); } else if (waitMs > 0) { auto tp = std::chrono::steady_clock::now() + std::chrono::milliseconds(waitMs); while (ready_.wait_until(lk, tp) != std::cv_status::timeout && items_.empty() && !exit_) { } } } template <typename T> bool SafeQueue<T>::pop_wait(T* v, int waitMs) { std::unique_lock<std::mutex> lk(*this); wait_ready(lk, waitMs); if (items_.empty()) { return false; } *v = std::move(items_.front()); items_.pop_front(); return true; } template <typename T> T SafeQueue<T>::pop_wait(int waitMs) { std::unique_lock<std::mutex> lk(*this); wait_ready(lk, waitMs); if (items_.empty()) { return T(); } T r = std::move(items_.front()); items_.pop_front(); return r; }