#pragma once #include #include #include template class blocking_queue { std::deque deque{}; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; bool cancelled = false; public: ~blocking_queue(); T take(); T &front() const; T &back() const; void push(const T&); void push(T&&); template< class... Args > void emplace(Args &&... args); void clear(); void cancel(); }; #define run_and_notify(block) \ mutex_guard g(this->lock); \ block \ pthread_cond_signal(&this->cond); template blocking_queue::~blocking_queue() { pthread_mutex_destroy(&lock); pthread_cond_destroy(&cond); } template T blocking_queue::take() { mutex_guard g(lock); cancelled = false; while (deque.empty() && !cancelled) pthread_cond_wait(&cond, &lock); if (cancelled) pthread_exit(nullptr); T ret(std::move(deque.front())); deque.pop_front(); return ret; } template void blocking_queue::push(const T &s) { run_and_notify({ deque.push_back(s); }) } template void blocking_queue::push(T &&s) { run_and_notify({ deque.push_back(std::move(s)); }) } template T &blocking_queue::front() const { mutex_guard g(lock); return deque.front(); } template T &blocking_queue::back() const { mutex_guard g(lock); return deque.back(); } template template void blocking_queue::emplace(Args &&... args) { run_and_notify({ deque.emplace_back(std::forward(args)...); }) } template void blocking_queue::clear() { mutex_guard g(lock); std::deque t; deque.swap(t); } template void blocking_queue::cancel() { run_and_notify({ cancelled = true; std::deque t; deque.swap(t); }) } #undef run_and_notify