基於std::mutex std::lock_guard std::condition_variable 和std::async實現的簡單同步隊列
C++多線程編程中通常會對共享的數據進行寫保護,以防止多線程在對共享數據成員進行讀寫時造成資源爭搶導致程序出現未定義的行為。通常的做法是在修改共享數據成員的時候進行加鎖--mutex。在使用鎖的時候通常是在對共享數據進行修改之前進行lock操作,在寫完之後再進行unlock操作,進場會出現由於疏忽導致由於lock之後在離開共享成員操作區域時忘記unlock,導致死鎖。
針對以上的問題,C++11中引入了std::unique_lock與std::lock_guard兩種數據結構。通過對lock和unlock進行一次薄的封裝,實現自動unlock的功能。std::unique_lock 與std::lock_guard都能實現自動加鎖與解鎖功能,但是std::unique_lock要比std::lock_guard更靈活,但是更靈活的代價是占用空間相對更大一點且相對更慢一點。
std::condition_variable 是條件變量,更多有關條件變量的定義參考維基百科。Linux 下使用 Pthread 庫中的 pthread_cond_*() 函數提供了與條件變量相關的功能, Windows 則參考 MSDN。
當 std::condition_variable 對象的某個 wait 函數被調用的時候,它使用 std::unique_lock(通過 std::mutex) 來鎖住當前線程。當前線程會一直被阻塞,直到另外一個線程在相同的 std::condition_variable 對象上調用了 notification 函數來喚醒當前線程。
std::condition_variable 對象通常使用 std::unique_lock<std::mutex> 來等待,如果需要使用另外的 lockable 類型,可以使用 std::condition_variable_any 類,本文後面會講到 std::condition_variable_any 的用法。
template<typename T> class SimpleSyncQueue { public: SimpleSyncQueue(){} ~SimpleSyncQueue(){} void Put(const T& element) { std::lock_guard<std::mutex> locker(m_mutex); m_queue.push_back(element); m_NotEmpty.notify_all(); } void Take(T& result) { std::unique_lock<std::mutex> locker(m_mutex); m_NotEmpty.wait(locker, [this](){cout << "take wait!" << endl; return !m_queue.empty(); }); result = m_queue.front(); m_queue.pop_front(); } bool Empty() { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.empty(); } size_t Size() { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.size(); } private: std::list<T> m_queue; std::mutex m_mutex; std::condition_variable m_NotEmpty; }; SimpleSyncQueue<int> queue; void Thread1func() { for (int i = 0; i < 10; i++) { queue.Put(i); cout << "size: "<<queue.Size() << endl; } } void Thread2func() { int res; for (int i = 0; i < 5; i++) { queue.Take(res); cout << "teke res: " << res << endl; } } void Test14() { std::future<void> future1 = std::async(std::launch::async,Thread1func); //Sleep(1000); std::future<void> future2 = std::async(std::launch::async, Thread2func); future1.wait(); future2.wait(); }
某次執行結果如下:
基於std::mutex std::lock_guard std::condition_variable 和std::async實現的簡單同步隊列