通知线程是不是可以在被通知线程等待锁定之前锁定?

Posted

技术标签:

【中文标题】通知线程是不是可以在被通知线程等待锁定之前锁定?【英文标题】:Is it possible for the notifying thread to lock before the notified thread's wait to lock?通知线程是否可以在被通知线程等待锁定之前锁定? 【发布时间】:2018-11-13 14:50:15 【问题描述】:

来自std::condition_variable::notify_one的示例代码。

我的问题是通知线程是否可以在通知线程的wait函数锁定之前锁定,因为notify操作不会阻塞当前线程?


代码:(我把原来的cmets删掉了)

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;

void waits()

    std::unique_lock<std::mutex> lk(cv_m);
    std::cout << "Waiting... \n";
    cv.wait(lk, []return i == 1;); //Waiting 
    std::cout << "...finished waiting. i == 1\n";
    done = true;


void signals()

    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Notifying falsely...\n";
    cv.notify_one(); //Notifying

    std::unique_lock<std::mutex> lk(cv_m);//Is it possible for this line to execute
                                         //before cv.waits() in waits() tries to lock ?
    i = 1;
    while (!done)
    
        std::cout << "Notifying true change...\n";
        lk.unlock();
        cv.notify_one(); 
        std::this_thread::sleep_for(std::chrono::seconds(1));
        lk.lock();
    


int main()

    std::thread t1(waits), t2(signals);
    t1.join();
    t2.join();

【问题讨论】:

是的,可以通过在等待线程之前通知线程来锁定。但它是如何使代码不安全的呢? @bartop 是的,你是对的.. 即使这样也不会使代码不安全。顺便说一句,是否有任何保证执行顺序的规则?还是只是未定义? 【参考方案1】:

在回答您的标题问题时,是的。 signals 线程可能在 waits 线程之前锁定。但在回答你真正的问题时,不,这不会导致僵局。

为什么?

因为在示例中,互斥锁由lk.unlock() 释放。在此解锁时,waits 线程将有机会锁定(然后在等待开始时再次解锁)。

这个循环一直持续到wait 线程用done 布尔值表示它已完成。

时间示例:

还有很多其他的,但在所有情况下,相关的对象和条件变量都受到互斥锁的保护。你不能有数据竞争或死锁。这个例子是合理的。

【讨论】:

谢谢福克斯先生。那么执行顺序根本无法保证,我不应该指望它对吗? @Rick 不,不是。这就是为什么您应该考虑所有可能的顺序来找出是否存在数据争用或死锁。 顺便说一句,我重新检查了 cppreference 的页面,注意到在输出部分,它正在写“可能的输出”,这可能间接证明了这一点。事实上,输出 cppreference 显示,我得到的是:“通知线程锁优先”... @Rick,情况可能会更糟。进一步阅读condition_variable,您会发现它可以无缘无故地虚假唤醒。这就是为什么您需要谓词(在本例中为 lambda)来检查等待条件是否已实际实现。并且您需要谓词使用的资源受到互斥锁的保护...... @Rick 你可以在这里制作它们:sequencediagram.org 至于关于等待的评论开始不对,我不确定你的意思。您似乎在说时序图中的相同内容。

以上是关于通知线程是不是可以在被通知线程等待锁定之前锁定?的主要内容,如果未能解决你的问题,请参考以下文章

四十Linux 线程——线程同步之条件变量

Java 中啥是快速、等待通知或忙等待?

进程_线程 之 --- 生产者消费者

java.lang.IllegalMonitorStateException:在等待()之前对象没有被线程锁定?

Linux学习_线程条件变量和状态转移图

有没有办法只向锁定屏幕发送推送通知?