在这段代码中,如何使用 notify 调用 wait() 调用?

Posted

技术标签:

【中文标题】在这段代码中,如何使用 notify 调用 wait() 调用?【英文标题】:How does the wait() call get invoked with notify in this code? 【发布时间】:2021-09-30 22:44:11 【问题描述】:

我有一个如下的 c++ 代码,它使用condition-variable 进行同步。

#include <iostream> 
#include <condition_variable>

int n = 4;
enum class Turn  FOO, BAR ;
Turn turn = Turn::FOO;

std::mutex mut;
std::condition_variable cv;

void foo() 
    for (int i = 0; i < n; i++) 
        std::unique_lock<std::mutex> lock(mut);

        // wait for signal from bar & turn == FOO
        cv.wait(lock, [] return turn == Turn::FOO; );

        std::cout << "foo" << std::endl;

        // unlock & signal bar
        lock.unlock();
        turn = Turn::BAR;
        cv.notify_one();
    


void bar() 
    for (int i = 0; i < n; i++) 
        std::unique_lock<std::mutex> lock(mut);

        // wait for signal from foo & turn == BAR
        cv.wait(lock, [] return turn == Turn::BAR; );

        std::cout << "bar" << std::endl;

        // unlock &  signal foo
        lock.unlock();
        turn = Turn::FOO;
        cv.notify_one();
    


int main() 
    std::thread thread_1(foo);
    std::thread thread_2(bar);
    thread_2.join();
    thread_1.join();
    
    return 0; 

观察到的输出:

问题:

foo() 中的cv.wait(lock, [] return turn == Turn::FOO; ); 一开始是如何被触发的?

根据我的阅读,带有谓词的wait() 调用相当于:while (!pred()) wait(lock); 。谓词开头为真(turn 的初始值为Turn::FOO),但是等待调用如何获得通知?关于wait(),我看到了这个:

以原子方式解锁锁,阻塞当前正在执行的线程,并将其添加到等待 *this 的线程列表中。执行 notify_all() 或 notify_one() 时,线程将被解除阻塞。它也可能被虚假地解除阻塞。解除阻塞后,无论什么原因,都会重新获取锁并等待退出。

但我看不到另一个线程(运行bar() 的线程)执行notify_one(),因为turn 仍然是FOO

【问题讨论】:

这段代码来自哪里? 【参考方案1】:

foo() 中的 cv.wait 一开始是如何被触发的?

它将由评估为true 的谓词触发。等效循环:

while (!pred()) 
    wait(lock);

不会调用wait() 一次(无论如何,第一次访问该行代码时)。

【讨论】:

如果是这种情况,即使从两个函数中删除了两个cv.notify_one() 调用,程序不应该打印 n 次“foo bar foo bar ...”吗? @skurup 不,因为其中一个功能确实会在某个时候进入等待状态,您需要通知它。除非你的日程安排是超级幸运的 ins 从 foo 到 bar 再回来,这样他们只会在轮到他们时才排队。 是的,现在知道了。 cv.wait(lock, [] return turn == Turn::FOO; ); 应该读作 Wait for signal from bar() if turn != FOOcv.wait(lock, [] return turn == Turn::BAR; ); 应该读作 wait for signal from foo() if turn != BAR. @skurup:好吧,如果这回答了您的问题 - 请点击复选标记接受。

以上是关于在这段代码中,如何使用 notify 调用 wait() 调用?的主要内容,如果未能解决你的问题,请参考以下文章

Java 线程通信之 wait/notify 机制

Java 线程通信之 wait/notify 机制

Java 线程通信之 wait/notify 机制

下一步是啥();在这段代码中?

如何在这段代码中在 PHP 中使用 mysqli

我将如何在这段代码中使用@mixin 和@include?