#pragma once #ifndef _NB_UTIL_THREADSAFE_QUEUE #define _NB_UTIL_THREADSAFE_QUEUE #include #include #include #include #include namespace nb { template class ThreadsafeQueue_impl; // Non-polymorphic template class ThreadsafeQueue_impl { public: bool empty() const { std::lock_guard lock(_mutex); return _queue.empty(); } unsigned int size() const { std::lock_guard lock(_mutex); return _queue.size(); } template void push(U&& val) { std::lock_guard lock(_mutex); _queue.push(std::forward(val)); _cond.notify_one(); } bool pop(std::shared_ptr& dest) { std::lock_guard lock(_mutex); if (_queue.empty()) { return false; } dest = std::make_shared(std::move(_queue.front())); _queue.pop(); return true; } std::shared_ptr popBlock() { std::unique_lock lock(_mutex); _cond.wait(lock, [&]{ return !_queue.empty(); }); auto ret = std::make_shared(std::move(_queue.front())); _queue.pop(); return ret; } protected: ThreadsafeQueue_impl() {} std::queue _queue; std::condition_variable _cond; mutable std::mutex _mutex; }; // Polymorphic template class ThreadsafeQueue_impl { public: bool empty() const { std::lock_guard lock(_mutex); return _queue.empty(); } unsigned int size() const { std::lock_guard lock(_mutex); return _queue.size(); } template void push(U&& val) { std::lock_guard lock(_mutex); std::shared_ptr newval = std::make_shared(std::forward(val)); _queue.push(newval); _cond.notify_one(); } bool pop(std::shared_ptr& dest) { std::lock_guard lock(_mutex); if (_queue.empty()) { return false; } dest = std::move(_queue.front()); _queue.pop(); return true; } std::shared_ptr popBlock() { std::unique_lock lock(_mutex); _cond.wait(lock, [&]{ return !_queue.empty(); }); auto ret = std::move(_queue.front()); _queue.pop(); return ret; } protected: ThreadsafeQueue_impl() {} std::queue> _queue; std::condition_variable _cond; mutable std::mutex _mutex; }; template class ThreadsafeQueue : public ThreadsafeQueue_impl::value> { public: using Implementation = ThreadsafeQueue_impl::value>; ThreadsafeQueue() = default; ~ThreadsafeQueue() = default; ThreadsafeQueue(ThreadsafeQueue& rhs) = delete; ThreadsafeQueue& operator=(ThreadsafeQueue& rhs) = delete; ThreadsafeQueue(ThreadsafeQueue&& rhs) = delete; ThreadsafeQueue& operator=(ThreadsafeQueue&& rhs) = delete; operator bool() const { return !Implementation::empty(); } }; } // namespace nb #endif // _NB_UTIL_THREADSAFE_QUEUE