最近看了下c++11的線程。看了不少博客,這里會引用到CSDN里Nine-days博客里的demo。
notify_one:喚醒等待線程中的一個。
notify_all:喚醒所有等待的線程。
wait:等待。需要其它的接口來喚醒。
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
//demo std::mutex mtx_syn; std::condition_variable cv_syn; std::condition_variable cv_syn_1; bool ready = false;
//線程A void threadA(int id) { while (1) { std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) { cv_syn.wait(lck); } // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_one(); // 喚醒等待線程中的一個 cv_syn.wait(lck); // 等待 } }
// 線程B void threadB(int id) { while (1) { //新創建的 unique_lock 對象管理 Mutex 對象 m,並嘗試調用 m.lock() 對 Mutex 對象進行上鎖,如果此時另外某個 unique_lock 對象已經管理了該 Mutex 對象 m,則當前線程將會被阻塞 std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) { cv_syn.wait(lck); } // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_one(); // 喚醒等待線程中的一個 cv_syn.wait(lck); } } // 線程C void threadC(int id) { while (1) { std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) cv_syn.wait(lck); // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_one(); // 喚醒等待線程中的一個線程 cv_syn.wait(lck); } } void go() { std::unique_lock<std::mutex> lck(mtx_syn); ready = true; cv_syn.notify_one(); // 喚醒等待線程中的一個線程 }
int main() { //線程同步 std::thread threads[5]; threads[0] = std::thread(threadA, 0); threads[1] = std::thread(threadB, 1); threads[2] = std::thread(threadC, 2); std::cout << "3 threads ready to race...\n"; go(); // go! for (auto& th : threads) th.join(); }
3 threads ready to race... thread 0 thread 1 thread 2 thread 0 thread 1 thread 2 thread 0 thread 1 thread 2 thread 0 thread 1 thread 2
通過main函數,知道實例化了3個線程。線程A,B,C在創建后被阻塞。go函數實現對線程的喚醒。
執行后發現go函數通過cv_syn.notify_one();喚醒的線程是A。
A線程,執行cv_syn.notify_one();喚醒的線程是B。
B線程,執行cv_syn.notify_one();喚醒的線程是C。
C線程,執行cv_syn.notify_one();喚醒的線程是A。
這里有一個沒弄懂的地方。通過cv_syn.notify_one()喚醒,是依次喚醒,而不是隨機。
#include <iostream> #include <thread> #include <condition_variable> #include <mutex> //demo std::mutex mtx_syn; std::condition_variable cv_syn; std::condition_variable cv_syn_1; bool ready = false; //線程A void threadA(int id) { while (1) { std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) { cv_syn.wait(lck); } // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_all(); // 喚醒所有等待線程:B和C,B和C將會競爭鎖 cv_syn.wait(lck); } } // 線程B void threadB(int id) { while (1) { //新創建的 unique_lock 對象管理 Mutex 對象 m,並嘗試調用 m.lock() 對 Mutex 對象進行上鎖,如果此時另外某個 unique_lock 對象已經管理了該 Mutex 對象 m,則當前線程將會被阻塞 std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) { cv_syn.wait(lck); } // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_all(); // 喚醒所有等待線程:A和C,它們將會競爭鎖 cv_syn.wait(lck); } } // 線程C void threadC(int id) { while (1) { std::unique_lock<std::mutex> lck(mtx_syn); while (!ready) cv_syn.wait(lck); // ... std::cout << "thread " << id << '\n'; Sleep(500); cv_syn.notify_all(); // 喚醒所有等待線程:A和B,它們將會競爭鎖 cv_syn.wait(lck); } } void go() { std::unique_lock<std::mutex> lck(mtx_syn); ready = true; cv_syn.notify_one(); // 喚醒等待線程中的一個線程 } int main() { //線程同步 std::thread threads[5]; threads[0] = std::thread(threadA, 0); threads[1] = std::thread(threadB, 1); threads[2] = std::thread(threadC, 2); std::cout << "3 threads ready to race...\n"; go(); // go! for (auto& th : threads) th.join(); }
3 threads ready to race... thread 0 thread 1 thread 2 thread 0 thread 1 thread 2 thread 0 thread 2 thread 0 thread 2 thread 0 thread 1 thread 0
通過輸出知道,cv_syn.notify_all()喚醒了等待的所有線程,但是這些被喚醒的線程需要去競爭鎖,只有獲取到鎖,才可以進行輸出。
而cv_syn.notify_one()則不是這樣,它沒有競爭。
這樣go里使用notify_one就不合適。應該改為notify_all. 三個線程就會對鎖進行競爭。
輸出如下
3 threads ready to race... thread 2 thread 1 thread 2 thread 1 thread 2 thread 1 thread 2 thread 0 thread 2 thread 0 thread 2 thread 0 thread 2 thread 0
