2013-04-08 18 views
12

C++ 11 std :: hat condition_variable, seine Wartefunktion istEreignisbenachrichtigung ohne Mutex

template< class Predicate > 
void wait(std::unique_lock<std::mutex>& lock, Predicate pred); 

Es erfordert eine Mutex.

Soweit ich es verstehe - seine notify_one kann ohne Synchronisierung aufgerufen werden (ich weiß, die idiomatische Art ist, es mit einem Mutex zu verwenden).

Ich habe ein Objekt, die intern bereits synchronisiert ist - so dass ich es nicht einen Mutex müssen schützen. Ein Thread sollte auf ein Ereignis warten, das mit diesem Objekt verknüpft ist, und andere würden benachrichtigt.

Wie macht man eine solche Benachrichtigung ohne Mutex in C++ 11? I.e. Es ist leicht mit einer condition_variable zu machen, aber es benötigt einen Mutex. Ich dachte über die Verwendung eines gefälschten Mutex-Typs nach, aber std :: mutex wurde in die Wait-Schnittstelle eingefügt.

Eine Option ist, ein std :: atomic_flag + Schlaf abzufragen, aber ich mag es nicht zu schlafen.

Antwort

11

Verwenden Sie std::condition_variable_any Sie können jede Klasse damit verwenden, die das BasicLockable Konzept implementiert.

Angesichts eines schlechten Gefühls über dies überprüft ich die Implementierung von std::condition_variable_any von libC++. Es stellt sich heraus, dass es eine einfache std::condition_variable zusammen mit einer std::shared_ptr zu einer std::mutex verwendet, so dass es definitiv einige Overhead beteiligt, ohne tiefer zu graben. (Es gibt einen anderen Beitrag hier auf SO, der das deckt, obwohl ich das zuerst suchen muss)
Als eine Sache davon würde ich wahrscheinlich empfehlen, Ihren Fall neu zu entwerfen, so dass Synchronisation wirklich nur durch einen Mutex erfolgt, der eine einfache Bedingung schützt Variable.

+0

Das ist genau was ich suche, war mir nicht bewusst. Vielen Dank! – qble

+0

"Es stellt sich heraus, dass es eine einfache std :: condition_variable zusammen mit einem std :: shared_ptr zu einem std :: mutex verwendet, so dass es definitiv einen Overhead gibt, ohne tiefer zu graben." - Interessant, sperrt es interne Mutex innerhalb von ** notify_one **? Was ist mit plain std :: condition_variable - sperrt es jeden Mutex mit ** notify_one **? – qble

+0

"In diesem Fall würde ich Ihnen wahrscheinlich empfehlen, Ihren Fall neu zu gestalten, so dass die Synchronisation wirklich nur durch einen Mutex erfolgt, der eine einfache Zustandsvariable schützt."- Ich muss nicht notify_one schützen. Warum brauche ich Mutex, die nur innerhalb eines Threads verwendet werden? – qble

5

In einigen Threading-Modellen (obwohl ich in modernen nicht bezweifle) ist der Mutex erforderlich, um die Bedingung Variable (nicht das Objekt, das Sie synchronisieren) vor gleichzeitigem Zugriff zu schützen. Wenn die Bedingungsvariable nicht durch einen Mutex geschützt ist, können Probleme mit der Bedingung selbst auftreten.

Siehe Why do pthreads’ condition variable functions require a mutex?

+2

Ich denke, std :: condition_variable_any :: notify_one braucht Mutex nicht zum Schutz - Das ist nach ISO. Wenn einige Architekturen den Schutz von notify_one erfordern würden, würde die Bibliothek das selbst tun, sonst wäre es nicht standardkonform. – qble

+1

Interessante Infos, danke. Wir haben den Kreis geschlossen. 'std :: condition_variable_any' enthält einen internen' std :: mutex' um sich selbst zu schützen. :-) –

+0

Das verstehe ich. Wenn ** notify_one ** nicht von ISO synchronisiert würde - dann benötigen wir einen externen Mutex. – qble

1

ich einen Gegenstand haben, die bereits intern synchronisiert - ich weiß nicht Mutex müssen sie schützen. Ein Thread sollte auf ein Ereignis warten, das mit diesem Objekt verknüpft ist, und andere würden dies melden.

Wenn Sie nicht halten den Mutex der wartenden Thread-Benachrichtigungen verpassen wird, unabhängig davon, ob Sie condition_variable oder condition_variable_any mit dem internen Mutex verwenden.

Sie müssen der Bedingungsvariablen mindestens ein Bit zusätzlicher Informationen zuordnen, und dieses Bit sollte durch einen Mutex geschützt sein.

+0

Ja, ich weiß darüber Bescheid, und das ist in dieser Situation akzeptabel. – qble

+0

Sie haben das Ende meines Satzes verpasst. Es gibt eine Race-Bedingung, wenn der Mutex nicht gehalten wird, wenn er diesen Zustand überprüft und dann auf die Zustandsvariable wartet. –

+0

Es gibt [nicht-kritische Race-Bedingung] (http://en.wikipedia.org/wiki/Race_condition#Critical_and_non-critical_race_conditions). es ist nicht UB. – qble