#pragma once #include #include template class BlockingQueue { std::deque deque{}; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; bool cancelled = false; public: ~BlockingQueue(); T take(); T &front(); T &back(); void put(const T&); void put(T&&); template< class... Args > void emplace_back(Args&&... args); void clear(); void cancel(); }; #define run_and_notify(block) \ pthread_mutex_lock(&this->lock); \ block \ pthread_cond_signal(&this->cond); \ pthread_mutex_unlock(&this->lock); template BlockingQueue::~BlockingQueue() { pthread_mutex_destroy(&lock); pthread_cond_destroy(&cond); } template T BlockingQueue::take() { pthread_mutex_lock(&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(); pthread_mutex_unlock(&lock); return ret; } template void BlockingQueue::put(const T &s) { run_and_notify({ deque.push_back(s); }) } template void BlockingQueue::put(T &&s) { run_and_notify({ deque.push_back(std::move(s)); }) } template T &BlockingQueue::front() { pthread_mutex_lock(&lock); auto &ret = deque.front(); pthread_mutex_unlock(&lock); return ret; } template T &BlockingQueue::back() { pthread_mutex_lock(&lock); auto &ret = deque.back(); pthread_mutex_unlock(&lock); return ret; } template template void BlockingQueue::emplace_back(Args &&... args) { run_and_notify({ deque.emplace_back(std::forward(args)...); }) } template void BlockingQueue::clear() { pthread_mutex_lock(&lock); std::deque t; deque.swap(t); pthread_mutex_unlock(&lock); } template void BlockingQueue::cancel() { run_and_notify({ cancelled = true; std::deque t; deque.swap(t); }) }