2008-09-16 12 views
41

Was sind die Vor-/Nachteile der Verwendung von pthread_cond_wait oder mit einem Semaphor? Ich bin für eine Zustandsänderung wie folgt warten:pthread_cond_wait versus Semaphor

pthread_mutex_lock(&cam->video_lock); 
while(cam->status == WAIT_DISPLAY) { 
    pthread_cond_wait(&cam->video_cond, &cam->video_lock); 
} 
pthread_mutex_unlock(&cam->video_lock); 

Mit einem richtig initialisiert Semaphore, ich glaube, ich es so tun könnte:

while(cam->status == WAIT_DISPLAY) { 
    sem_wait(&some_semaphore); 
} 

Was sind die Vor- und Nachteile der einzelnen Methoden sind?

+0

Ich habe erkannt, dass „richtig initialisiert Semaphore“ ist schlecht definiert. Ist der Semaphor auf 1 oder auf 0 gesetzt? Ich würde sagen, es sollte auf 0 gesetzt werden. Dann schützt das Semaphor cam-> Status oder nicht? – Blaisorblade

+0

Im zweiten Snippet, wie in anderen Antworten erwähnt, wird Ihr Thread blockiert, während Mutex nicht freigegeben ist. Also wird Ihre 'sem_wait' Methode niemals zurückkehren, da kein anderer Thread den Mutex erzwingen und' sem_signal' aufrufen kann. Allerdings werde ich nicht was tun, wenn ich Mutex vor 'sem_wait' freigebe und nach dem Warten wieder benötige. Ich weiß, dass diese Schritte nicht atomar sind, also was wird passieren? – sevenkplus

Antwort

58

Ein Semaphor ist sauber zu einem Produzenten-Verbraucher-Modell geeignet, obwohl es andere Verwendungen hat. Ihre Programmlogik ist dafür verantwortlich, dass die richtige Anzahl von Posts für die Anzahl der Wartezeiten erstellt wird. Wenn du einen Semaphor postest und noch niemand darauf wartet, dann machen sie sofort weiter. Wenn Ihr Problem so ist, dass es in Bezug auf den Zählwert eines Semaphors erklärt werden kann, sollte es leicht mit einem Semaphor zu lösen sein.

Eine Zustandsvariable ist in mancher Hinsicht etwas fehlerverzeihender. Sie können zum Beispiel cond_broadcast verwenden, um alle Kellner aufzuwecken, ohne dass der Produzent weiß, wie viele es sind. Und wenn Sie einen Condvar signalisieren, während niemand darauf wartet, passiert nichts. Das ist gut, wenn Sie nicht wissen, ob ein Hörer interessiert ist. Es ist auch der Grund, warum der Zuhörer den Zustand immer mit dem vor dem Warten gehaltenen Mutex überprüfen sollte - wenn sie dies nicht tun, können sie ein Signal verpassen und nicht bis zum nächsten aufwachen (was niemals sein könnte).

So eine Zustandsvariable ist geeignet, interessierten Parteien mitzuteilen, dass sich der Status geändert hat: Sie erwerben den Mutex, ändern den Status, signalisieren (oder senden) den Condvar und geben den Mutex frei. Wenn dies Ihr Problem beschreibt, befinden Sie sich im Condvar-Gebiet. Wenn unterschiedliche Zuhörer an verschiedenen Zuständen interessiert sind, können Sie sie einfach senden, und sie werden dann nacheinander aufwachen, herausfinden, ob sie den gewünschten Zustand gefunden haben und wenn nicht, noch einmal warten.

Es ist in der Tat sehr gnadenlos, so etwas mit einem Mutex und einem Semaphor zu versuchen. Das Problem tritt auf, wenn Sie den Mutex nehmen, einen Zustand überprüfen und dann auf dem Semaphor auf Änderungen warten wollen. Wenn Sie den Mutex nicht atomar freigeben und auf den Semaphor warten können (was bei Pthreads nicht möglich ist), warten Sie auf den Semaphor, während Sie den Mutex halten. Dies blockiert den Mutex, was bedeutet, dass andere es nicht nehmen können, um die Änderung vorzunehmen, die dir wichtig ist. Sie werden also versucht sein, einen weiteren Mutex hinzuzufügen, der von Ihren spezifischen Anforderungen abhängt. Und vielleicht noch ein Semaphor. Das Ergebnis ist im Allgemeinen ein falscher Code mit schädlichen Rennbedingungen.

Bedingungsvariablen umgehen dieses Problem, da der Aufruf von cond_wait den Mutex automatisch freigibt und ihn für andere Benutzer freigibt. Der Mutex wird zurückgewonnen, bevor cond_wait zurückkehrt.

IIRC Es ist möglich, eine Art Condvar nur mit Semaphoren zu implementieren, aber wenn der Mutex, den du implementierst, um mit dem Condvar zu arbeiten, trelock benötigt, dann ist es ein ernsthafter Kopfkratzer, und zeitgesteuerte Wartezeiten sind out . Nicht empfohlen. Gehen Sie also nicht davon aus, dass irgendetwas, was Sie mit einer Condvar machen können, mit Semaphoren gemacht werden kann. Außerdem können Mutexe natürlich nette Verhaltensweisen haben, denen Semaphore fehlen, hauptsächlich die Prioritätsinversionsvermeidung.

0

In Ihrem zweiten Snippet erhalten Sie die Sperre viele Male und geben sie niemals frei.

Im Allgemeinen kann der Zustand, in dem Sie sich befinden, vollständig durch einen Semaphor ausgedrückt werden, dann können Sie genau das verwenden. Eine Sperrstruktur ist kleiner und erfordert weniger atomare Operationen zum Prüfen/Setzen/Freigeben.

Andernfalls, wenn der Zustand komplex ist und verschiedene Teile des Codes auf unterschiedliche Bedingungen der gleichen Variable warten (zB hier wollen Sie x < 10; dort wollen Sie y> x), verwenden Sie Cond_wait.

+0

Das zweite Snippet ist korrekt - ein Wakeup wird immer von jemandem verursacht, der den Semaphor signalisiert. – Blaisorblade

+0

@Blaisorblade, das Aufwecken ist korrekt, die Statusüberprüfung ist nein, weil sie nicht überwacht wird. –

+0

Das ist ein anderes Problem als das, was diese Antwort beschreibt - "in Ihrem zweiten Schnipsel, Sie bekommen die Sperre viele Male, nie veröffentlicht". Ich erwähne dieses Problem in meiner Antwort oben (obwohl nicht sehr spezifisch). Aber während ich den Code noch einmal anschaue, merke ich, dass man nicht wirklich sagen kann, ob das zweite Snippet korrekt ist oder nicht, weil zu viele Details fehlen (siehe meinen Kommentar zu der Frage). Aber ich formulierte meinen Kommentar falsch - ich hätte sagen sollen "das Problem, das Sie erwähnen, ist nicht da, weil ...". – Blaisorblade

19

Conditionals lassen Sie einige Dinge tun, die Semaphoren nicht tun.

Angenommen, Sie haben einen Code, der einen Mutex erfordert, m genannt. Es muss jedoch warten, bis ein anderer Thread seine Aufgabe beendet hat, so dass es auf einen Semaphor namens s wartet. Nun wird jeder Thread, der m benötigt, blockiert, obwohl der Thread, der m hat, auf s wartet. Diese Art von Situationen kann unter Verwendung von Bedingungen gelöst werden. Wenn Sie auf eine Bedingung warten, wird der aktuell gehaltene Mutex freigegeben, sodass andere Threads den Mutex abrufen können. Also zurück zu unserem Beispiel und angenommen, dass c anstelle von s verwendet wurde. Unser Thread erwirbt nun m und wartet dann auf c. Dies gibt m frei, damit andere Threads fortfahren können. Wenn c verfügbar wird, wird m wieder erworben, und unser ursprünglicher Thread kann munter weitergehen.

Mit bedingten Variablen können Sie auch alle Threads warten auf eine bedingte Variable, um über pthread_cond_broadcast fortzufahren. Darüber hinaus können Sie auch eine zeitgesteuerte Wartezeit durchführen, damit Sie nicht für immer am Ende warten.

Natürlich, manchmal brauchen Sie keine bedingten Variablen, also kann je nach Ihren Anforderungen, die eine oder andere besser sein.

+3

Dies ist eine gute Antwort. Um der Beschreibung hinzuzufügen, was die Bedingung im Vergleich zur beschriebenen Kombination aus Mutex und Semaphor einzigartig macht, ist, dass die Bedingung das Mutex/Semaphor-Paar atomar manipuliert !! –

4

Das zweite Snippet ist rassig, tu das nicht.

Die anderen Antworten haben eine nette Diskussion der relativen Vorzüge; Ich füge einfach hinzu, dass pthread_cond_broadcast ein klarer Vorteil von Zustandsvariablen ist.

Darüber hinaus bin ich eher gewohnt, Variablen dafür zu konditionieren, wie sie in Java verwendet werden, auch weil sie Ihnen helfen, Rennen zu vermeiden, wenn Sie die geteilten Flags überprüfen.

In der Tat, in der zweiten Schnipsel haben Sie keine Sperre, die das Lesen von Cam-> Status zu schützen, so dass es durch ein Datenrennen zugegriffen wird. Die meisten Plattformen werden Sie in diesem speziellen Beispiel durchkommen lassen, aber mit undefinierter Semantik, nach POSIX und nach dem Speichermodell der nächsten C/C++ - Standards.

In der Tat ist eine echte Wettlaufsituation möglich, wenn ein anderer Thread eine neue Nockenstruktur zuweist und Nocken überschreibt; Der wartende Thread sieht möglicherweise die Aktualisierung des "cam" -Zeigers, ohne die Initialisierung von cam-> status zu sehen. In der Tat, der zweite Ausschnitt fragt in diesem Fall und im Allgemeinen nach Ärger.

http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/

+0

Tatsächlich könnte der Semaphor selbst im zweiten Snippet das Statusflag schützen (oder nicht) (obwohl ich mir ein gutes Sperrprotokoll dafür nicht vorstellen kann). – Blaisorblade