notifyall не работает в многопоточности C ++. Вызывая тупик

#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 & ДАЖЕ номера синхронизированы (по одному). Код работает нормально большую часть времени.
Но иногда он заходит в тупик.
Это происходит, когда нечетный поток нажимает notify_all, но до того, как четный поток просыпается, он нечетный поток получает блокировку и затем, когда он находит условие ожидания, он переходит в ожидание, пока четный поток еще не проснулся.
Выйти из сделки Я попытался заменить notify_all на notify_one,
но проблема все еще сохраняется. Есть ли какие-либо изменения в дизайне?
Или я что-то упускаю полностью? * /

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), но и рекомендуется, так как вы уменьшите вероятность того, что релизер жадно повторно войдет в критический блок. Вы получите больше понимания этого последнего пункта Вот.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]