#pragma once #include #include #include #include template class UnboundedQueue { public: explicit UnboundedQueue(bool block_ = true) : _block(block_) { } void push(const T& item_) { { std::lock_guard guard(_queue_lock); _queue.push(item_); } _condition.notify_one(); } void push(T&& item_) { { std::lock_guard guard(_queue_lock); _queue.push(std::move(item_)); } _condition.notify_one(); } template void emplace(Args&&... args_) { { std::lock_guard guard(_queue_lock); _queue.emplace(std::forward(args_)...); } _condition.notify_one(); } bool try_push(const T& item_) { { std::unique_lock lock(_queue_lock, std::try_to_lock); if(!lock) return false; _queue.push(item_); } _condition.notify_one(); return true; } bool try_push(T&& item_) { { std::unique_lock lock(_queue_lock, std::try_to_lock); if(!lock) return false; _queue.push(std::move(item_)); } _condition.notify_one(); return true; } //TODO: push multiple T at once bool pop(T& item_) { std::unique_lock guard(_queue_lock); _condition.wait(guard, [&]() { return !_queue.empty() || !_block; }); if(_queue.empty()) return false; item_ = std::move(_queue.front()); _queue.pop(); return true; } bool try_pop(T& item_) { std::unique_lock lock(_queue_lock, std::try_to_lock); if(!lock || _queue.empty()) return false; item_ = std::move(_queue.front()); _queue.pop(); return true; } std::size_t size() const { std::lock_guard guard(_queue_lock); return _queue.size(); } bool empty() const { std::lock_guard guard(_queue_lock); return _queue.empty(); } void block() { std::lock_guard guard(_queue_lock); _block = true; } void unblock() { { std::lock_guard guard(_queue_lock); _block = false; } _condition.notify_all(); } bool blocking() const { std::lock_guard guard(_queue_lock); return _block; } private: mutable std::mutex _queue_lock; private: bool _block; std::queue _queue; std::condition_variable _condition; };