c++11 Condition Variable notify_one notify_all wait


最近看了下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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM