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++ 多线程中不起作用。造成僵局的主要内容,如果未能解决你的问题,请参考以下文章
@synchronized 在 MRC 中不起作用,我的应用程序在多线程中崩溃
多处理、动态嵌套管理器在 Windows 中不起作用(在 Mac 上很好)