#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;
}
/ *上面是打印ODD&amp;的程序。 EVEN数字以同步方式(逐个)。代码在大多数情况下工作正常。 但它有时会陷入僵局。 当奇数线程击中notify_all但在偶数线程唤醒之前,奇数线程获取锁定然后当它找到等待条件时它进入等待而偶数线程没有被唤醒时发生这种情况。 离开一个下台的情况。我尝试将notify_all替换为notify_one, 但问题仍然存在。设计需要改变吗? 还是有什么我完全错过的? * /
答案 0 :(得分: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获得更多见解。