#ifndef FACT_Queue #define FACT_Queue #include #include template class Queue : std::deque { std::mutex fMutex; // Mutex needed for the conditional std::condition_variable fCond; // Conditional enum state_t { kRun, kWait, kStop }; state_t fState; // Stop signal for the thread typedef std::function callback; callback fCallback; // Callback function called by the thread std::thread fThread; // Handle to the thread void Thread() { std::unique_lock lock(fMutex); while (1) { while (std::deque::empty() && fState==kRun) fCond.wait(lock); if (fState==kStop) break; if (fState==kWait && std::deque::empty()) break; const T val = std::deque::front(); std::deque::pop_front(); // Theoretically, we can loose a signal here, but this is // not a problem, because then we detect a non-empty queue lock.unlock(); if (fCallback) fCallback(val); lock.lock(); } } public: Queue(const callback &f) : fState(kRun), fCallback(f) { fThread = std::thread(std::bind(&Queue::Thread, this)); } ~Queue() { stop(); join(); } void post(const T &val) { const std::lock_guard lock(fMutex); std::deque::push_back(val); fCond.notify_one(); } void wait() { fMutex.lock(); fState = kWait; fCond.notify_one(); fMutex.unlock(); } void stop() { fMutex.lock(); fState = kStop; fCond.notify_one(); fMutex.unlock(); } void join() { // This can happen is the thread is not running anymore try { fThread.join(); } catch (const std::system_error &) { } } }; #endif