2017-03-22 2 views
1
#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; 
} 

/* Ci-dessus est le programme pour imprimer ODD & numéros EVEN de façon synchronisée (un par un). Le code fonctionne très bien la plupart du temps. Mais il est parfois dans une impasse. Cela se produit lorsque le thread impaire frappe notify_all mais avant que le thread pair ne se réveille, le thread impair acquiert le verrou puis, lorsqu'il trouve la condition wait, il attend que le thread pair ne se réveille pas. Quitter une situation de dealock. J'ai essayé de remplacer notify_all à notify_one, mais le problème persiste toujours. Y a-t-il un changement dans la conception requise? Ou y a-t-il quelque chose qui me manque complètement? */notifyall ne fonctionne pas en multithreading C++. Cause blocage

+0

Vous devez vous assurer que 'thread_even()' appelle 'even.wait()' avant 'thread_odd()' appelle 'even.notify_all()'. – mkcms

Répondre

1

En règle générale dans un programme concurrent, lorsque vous souhaitez accéder à une ressource partagée pour la lire et la modifier (dans votre cas, l'opérateur modulo sur num est en première lecture et num ++ est en écriture), vous devez obtenir un accès exclusif mutuel à cette ressource et pas libérer jusqu'à ce que vous avez terminé avec cette ressource.

Votre verrou va être libéré lorsqu'il existe la portée if-statement, donc vous ne suivez pas cette règle.

Si vous modifiez votre code comme suit, vous ne l'impasse:

#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; 
} 

Remarquez comment je libère le verrou avant d'aviser. En C++, ce n'est pas seulement possible (contrairement à Java) mais recommandé car vous diminuerez les chances que le déclencheur rentre goulûment dans le bloc critique. Vous obtiendrez d'autres informations sur ce dernier point here.

+0

Chef-d'œuvre. J'aurais dû penser ça. Merci beaucoup . – user3798283