notifyall 在 C++ 多线程中不起作用。造成僵局

Posted

技术标签:

【中文标题】notifyall 在 C++ 多线程中不起作用。造成僵局【英文标题】:notifyall not working in C++ multithreading . Causing deadlock 【发布时间】:2017-03-22 20:10:31 【问题描述】:
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
using namespace std;
int num = 1;
#define NUM 20
condition_variable odd;
condition_variable even;
mutex mut;
void thread_odd()

        while(num < NUM -1)
        
            if(num%2 != 1)
            
                  unique_lock<mutex> lock(mut);
                  odd.wait(lock);
            
            cout<<"ODD : "<<num<<endl;
            num++;
            even.notify_all();  // Line X
        

void thread_even()

        while(num < NUM )
        
            if(num%2 != 0)
            
                  unique_lock<mutex> lock(mut);
                  even.wait(lock);
            
            cout<<"EVEN : "<<num<<endl;
            num++;
            odd.notify_all();
        

int main()

       thread t1(thread_odd), t2(thread_even);
       t1.join();
       t2.join();
       return 0;

/* 以上是同步打印奇偶数的程序(一个一个)。代码大部分时间都运行良好。 但它有时会陷入僵局。 当奇数线程正在点击 notify_all 但在偶数线程唤醒之前,奇数线程获取锁,然后当它找到等待条件时,它进入等待状态,而偶数线程尚未唤醒。 离开脱壳状态。我尝试将 notify_all 替换为 notify_one , 但问题仍然存在。是否需要对设计进行任何更改? 或者有什么我完全想念的吗? */

【问题讨论】:

您需要确保thread_even()thread_odd() 调用even.notify_all() 之前调用even.wait() 【参考方案1】:

作为并发程序中的一般规则,当您要访问共享资源以读取和修改它时(在您的情况下,num上的模运算符是先读取,num++是写入),您需要获得互斥访问该资源并且不要释放它,直到您使用完该资源。

当它存在 if 语句范围时,您的锁将被释放,因此您不遵守此规则。

如果你修改你的代码如下,你就不会死锁:

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
using namespace std;
int num = 1;
#define NUM 20
condition_variable odd;
condition_variable even;
mutex mut;
void thread_odd()

    while(num < NUM -1)
    
        unique_lock<mutex> lock(mut);
        if(num%2 != 1)
        
            odd.wait(lock);
        
        cout<<"ODD : "<<num<<endl;
        num++;
        lock.unlock();
        even.notify_all();  // Line X
    

void thread_even()

    while(num < NUM )
    
        unique_lock<mutex> lock(mut);
        if(num%2 != 0)
        
            even.wait(lock);
        
        cout<<"EVEN : "<<num<<endl;
        num++;
        lock.unlock();
        odd.notify_all();
    

int main()

    thread t1(thread_odd), t2(thread_even);
    t1.join();
    t2.join();
    return 0;

在通知之前注意我是如何释放锁的。在 C++ 中,这不仅是可能的(与 Java 相对),而且是推荐的,因为您将减少释放者贪婪地重新进入关键块的机会。您将获得对最后一点here 的更多见解。

【讨论】:

杰作。早该想到的。非常感谢。

以上是关于notifyall 在 C++ 多线程中不起作用。造成僵局的主要内容,如果未能解决你的问题,请参考以下文章

多部分上传在 QObject 中不起作用移动到线程

@synchronized 在 MRC 中不起作用,我的应用程序在多线程中崩溃

VB6 GUI 在多线程 COM 环境中不起作用

多处理、动态嵌套管理器在 Windows 中不起作用(在 Mac 上很好)

Java多线程学习——waitnotify和notifyAll

为啥模板参数推导在 C++ 中不起作用?