(Original) C ++ synchronous queue
Synchronous queue as a thread-safe area of data sharing, data read often used between threads, such as semi-synchronous, semi-synchronous asynchronous queue thread pool.
It is actually relatively simple to use list, locks and condition variables, condition variable action is to wait for notification in the queue is full or empty time. Look at a simple synchronization queue:
#include <thread> #include <condition_variable> #include <mutex> #include <list> #include <iostream> using namespace std; template<typename T> class SimpleSyncQueue { public: void Put(const T& x) { std::lock_guard<std::mutex> locker(m_mutex); m_queue.push_back(x); m_notEmpty.notify_one(); } void Take(T& x) { std::unique_lock<std::mutex> locker(m_mutex); m_notEmpty.wait(locker, [this]{return !m_queue.empty();}); x = m_queue.front(); m_queue.pop_front(); } private: std::list<T> m_queue; std::mutex m_mutex; std::condition_variable_any m_notEmpty; };
Look synchronous queue with a ceiling:
if (m_needStop) return; list = std::move(m_queue); m_notFull.notify_one(); } void Take(T& t) { std::unique_lock<std::mutex> locker(m_mutex); m_notEmpty.wait(locker, [this]{return m_needStop || NotEmpty(); }); if (m_needStop) return; t = m_queue.front(); m_queue.pop_front(); m_notFull.notify_one(); } void Stop() { { std::lock_guard<std::mutex> locker(m_mutex); m_needStop = true; } m_notFull.notify_all(); m_notEmpty.notify_all(); } bool Empty() { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.empty(); } bool Full() { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.size() == m_maxSize; } size_t Size() { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.size(); } int Count() { return m_queue.size(); } private: bool NotFull() const { bool full = m_queue.size() >= m_maxSize; if (full) cout << "full, waiting,thread id: " << this_thread::get_id() << endl; return !full; } bool NotEmpty() const { bool empty = m_queue.empty(); if (empty) cout << "empty,waiting,thread id: " << this_thread::get_id() << endl; return !empty; } template<typename F> void Add(F&&x) { std::unique_lock< std::mutex> locker(m_mutex); m_notFull.wait(locker, [this]{return m_needStop || NotFull(); }); return; if (m_needStop) m_queue.push_back (STD :: Forward <F.> (X)); m_notEmpty.notify_one (); } Private: STD :: List <T> m_queue; // buffer std :: mutex m_mutex; // mutex and condition variables in combination std :: condition_variable m_notEmpty; // not empty the condition variable std :: condition_variable m_notFull; // not full condition variable int m_maxSize; // synchronization maximum queue size BOOL m_needStop; // stop sign };
Test code is relatively simple, I do not write. The actual application will be used later in the thread pool.
Synchronous queue as a thread-safe area of data sharing, data read often used between threads, such as semi-synchronous, semi-synchronous asynchronous queue thread pool.
It is actually relatively simple to use list, locks and condition variables, condition variable action is to wait for notification in the queue is full or empty time. Look at a simple synchronization queue:
#include <thread> #include <condition_variable> #include <mutex> #include <list> #include <iostream> using namespace std; template<typename T> class SimpleSyncQueue { public: void Put(const T& x) { std::lock_guard<std::mutex> locker(m_mutex); m_queue.push_back(x); m_notEmpty.notify_one(); } void Take(T& x) { std::unique_lock<std::mutex> locker(m_mutex); m_notEmpty.wait(locker, [this]{return !m_queue.empty();}); x = m_queue.front(); m_queue.pop_front(); } private: std::list<T> m_queue; std::mutex m_mutex; std::condition_variable_any m_notEmpty; };
Look synchronous queue with a ceiling:
if (m_needStop) return; list = std::move(m_queue); m_notFull.notify_one(); } void Take(T& t) { std::unique_lock<std::mutex> locker(m_mutex); m_notEmpty.wait(locker, [this]{return m_needStop || NotEmpty(); }); if (m_needStop) return; t = m_queue.front(); m_queue.pop_front(); m_notFull.notify_one(); } void Stop() { { std::lock_guard<std::mutex> locker(m_mutex); m_needStop = true; } m_notFull.notify_all(); m_notEmpty.notify_all(); } bool Empty() { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.empty(); } bool Full() { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.size() == m_maxSize; } size_t Size() { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.size(); } int Count() { return m_queue.size(); } private: bool NotFull() const { bool full = m_queue.size() >= m_maxSize; if (full) cout << "full, waiting,thread id: " << this_thread::get_id() << endl; return !full; } bool NotEmpty() const { bool empty = m_queue.empty(); if (empty) cout << "empty,waiting,thread id: " << this_thread::get_id() << endl; return !empty; } template<typename F> void Add(F&&x) { std::unique_lock< std::mutex> locker(m_mutex); m_notFull.wait(locker, [this]{return m_needStop || NotFull(); }); return; if (m_needStop) m_queue.push_back (STD :: Forward <F.> (X)); m_notEmpty.notify_one (); } Private: STD :: List <T> m_queue; // buffer std :: mutex m_mutex; // mutex and condition variables in combination std :: condition_variable m_notEmpty; // not empty the condition variable std :: condition_variable m_notFull; // not full condition variable int m_maxSize; // synchronization maximum queue size BOOL m_needStop; // stop sign };
Test code is relatively simple, I do not write. The actual application will be used later in the thread pool.