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