2016-07-04 6 views
1

ich folgendes Szenario haben:Nicht alle Fäden condition_variable.notify_all gemeldet()

condition_variable cv; 
mutex mut; 

// Thread 1: 
void run() { 
    while (true) { 
     mut.lock(); 
     // create_some_data(); 
     mut.unlock(); 
     cv.notify_all();   
    } 
} 

// Thread 2 
void thread2() { 
    mutex lockMutex; 
    unique_lock<mutex> lock(lockMutex); 
    while (running) { 
     cv.wait(lock); 
     mut.lock(); 
     // copy data 
     mut.unlock(); 
     // process data 
    } 
} 

// Thread 3, 4... - same as Thread 2 

Ich betreibe Thread 1 die ganze Zeit neue Daten zu erhalten. Andere Threads warten mit condition_variable, bis neue Daten verfügbar sind, kopieren sie dann und arbeiten daran. Die von Threads ausgeführte Arbeit unterscheidet sich in der Zeit, die bis zum Ende benötigt wird. Die Idee ist, dass Threads nur dann neue Daten erhalten, wenn sie mit dem alten fertig sind. Daten, die in der Zwischenzeit erhalten wurden, dürfen "vermisst" werden. Ich verwende keinen geteilten Mutex (nur um auf Daten zuzugreifen), weil ich nicht möchte, dass Threads voneinander abhängen.

Oben Code funktioniert gut auf Windows, aber jetzt ich es auf Ubuntu laufen und ich bemerkte, dass nur ein Thread benachrichtigt wird, wenn notify_all() aufgerufen wird und die anderen nur hängt an wait(). Warum ist das? Benötigt Linux einen anderen Ansatz für die Verwendung von condition_variable?

+1

'Ich benutze keinen geteilten Mutex (nur um auf Daten zuzugreifen), weil ich nicht möchte, dass Threads voneinander abhängen. - Aber die Verwendung der Bedingungsvariablen ** erfordert ** geteilten Mutex. Kein anderer Weg. – Tsyvarev

Antwort

2

Es funktioniert durch Glück.

Der Mutex und die Bedingungsvariable sind zwei Teile desselben Konstrukts. Sie können Mutexe und Cvs nicht mischen und abgleichen.

versuchen Sie dies:

void thread2() { 
    unique_lock<mutex> lock(mut); // use the global mutex 
    while (running) { 
     cv.wait(lock); 
     // mutex is already locked here 
     // test condition. wakeups can be spurious 
     // copy data 
     lock.unlock(); 
     // process data 

     lock.lock(); 
    } 
} 
+0

Danke euch allen für Antworten auf was scheinbar einfacher und dummer Fehler ist. Ich habe dies als Antwort akzeptiert, da es auch meine Anforderungen erfüllt, Mutex für den Rest der Schleife nicht zu sperren. – Pawel

1

Per this documentation:

Jeder Thread, der auf std warten will :: condition_variable muss

  1. acquire a std :: unique_lock, auf dem gleichen Mutex wie verwendet die gemeinsame Variable zu schützen
  2. führen Sie wait, wait_for oder wait_until aus. Die Warteoperationen geben den Mutex automatisch frei und unterbrechen die Ausführung des Threads .
  3. Wenn die Bedingungsvariable benachrichtigt wird, eine Zeitüberschreitung abläuft oder eine unerwünschte Wakeup auftritt, wird der Thread geweckt, und der Mutex wird atomar wiedererlangt. Der Thread sollte dann den Zustand überprüfen und das Warten fortsetzen, wenn das Aufwecken falsch war.

Dieser Code

void thread2() { 
    mutex lockMutex; 
    unique_lock<mutex> lock(lockMutex); 
    while (running) { 

der das nicht tun.

2

Ihr Code zeigt UB sofort an, da er die einzigartige Sperre erneut verriegelt, die der Computer beim Beenden der Wartezeit erneut gesperrt hat.

Es gibt andere Probleme, wie das Aufspüren von unerwünschten Wakeups.

Schließlich cv benachrichtigen alle onky notifiziert derzeit wartende Threads. Wenn ein Thread später auftaucht, keine Würfel.

Verwandte Themen