2009-07-16 9 views
44

Ich lerne Pthread und warte Bedingungen. Soweit ich wie ein typischer wartenden Thread sagen kann, ist:Pthread und Wartebedingungen

pthread_mutex_lock(&m); 
while(!condition) 
    pthread_cond_wait(&cond, &m); 
// Thread stuff here 
pthread_mutex_unlock(&m); 

Was ich nicht verstehe ist, warum while(!condition) die Linie notwendig ist, auch wenn ich pthread_cond_signal() verwenden den Faden zu wecken.

Ich kann das verstehen, wenn ich pthread_cond_broadcast() verwende ich brauche Bedingung zu testen, weil ich alle wartenden Threads aufwachen und einer von ihnen die Bedingung machen kann wieder falsch vor den Mutex Entriegeln (und damit die Ausführung zu einem anderen aufgeweckt übertragen Thread, der an diesem Punkt nicht ausgeführt werden soll). Aber wenn ich pthread_cond_signal() verwende, wache ich nur ein Thread, so muss die Bedingung wahr sein. So könnte der Code wie folgt aussehen:

pthread_mutex_lock(&m); 
pthread_cond_wait(&cond, &m); 
// Thread stuff here 
pthread_mutex_unlock(&m); 

Ich lese etwas über falsche Signale, die passieren können. Ist das (und nur das) der Grund? Warum sollte ich falsche Singnals haben? Oder gibt es noch etwas, das ich nicht verstehe?

Ich gehe davon aus das Signal Code ist wie folgt:

pthread_mutex_lock(&m); 
condition = true; 
pthread_cond_signal(&cond); // Should wake up *one* thread 
pthread_mutex_unlock(&m); 

Antwort

43

Der wirkliche Grund, warum Sie pthread_cond_wait in eine while-Schleife setzen sollten, ist nicht wegen eines unechten Wakeups. Selbst wenn Ihre Zustandsvariable kein falsches Wakeup aufweist, benötigen Sie immer noch die Schleife, um einen allgemeinen Fehlertyp zu erfassen. Warum? Überlegen Sie, was passieren kann, wenn mehrere Threads auf dem gleichen Zustand warten:

Thread 1       Thread 2   Thread 3 
check condition (fails) 
(in cond_wait) unlock mutex 
(in cond_wait) wait 
           lock mutex 
           set condition 
           signal condvar 
           unlock mutex 
                lock mutex 
                check condition (succeeds) 
                do stuff 
                unset condition 
                unlock mutex 
(in cond_wait) wake up 
(in cond_wait) lock mutex 
<thread is awake, but condition 
is unset> 

Das Problem hierbei ist, dass der Thread den Mutex vor warten freigeben müssen, möglicherweise einen anderen Thread erlaubt zu ‚stehlen‘ was auch immer das Gewinde für wartet. Wenn nicht garantiert wird, dass nur ein Thread auf diese Bedingung warten kann, ist es falsch anzunehmen, dass die Bedingung gültig ist, wenn ein Thread aufwacht.

+1

genau. abgestimmt. das sollte mehr Aufmerksamkeit bekommen als die angenommene Antwort. –

15

Angenommen, Sie nicht die Bedingung überprüfen. Dann in der Regel können Sie die folgende schlechte Sache nicht vermeiden geschieht (zumindest, können Sie es nicht in eine Zeile Code vermeiden):

Sender        Receiver 
locks mutex 
sets condition 
signals condvar, but nothing 
    is waiting so has no effect 
releases mutex 
            locks mutex 
            waits. Forever. 

Natürlich Ihr zweites Codebeispiel könnte dies vermeiden, indem Sie:

Dann wäre es sicherlich der Fall, dass, wenn es nur höchstens einen Empfänger gibt, und wenn cond_signal die einzige Sache wäre, die es aufwecken könnte, würde es immer nur aufwachen, wenn die Bedingung eingestellt war würde keine Schleife benötigen. nos deckt ab, warum das zweite "wenn" nicht wahr ist.

+0

Ich sehe, so ein "if" wird aus einem logischen Grund benötigt (endlose Wartezeit), aber eine Weile ist tatsächlich aufgrund von Implementierungsfragen erforderlich (Störsignale). – Emiliano

+0

Ja, als ich zum ersten Mal die Pthreads-Bibliothek verwendet habe, habe ich dieselbe Frage gestellt. Ich habe es versäumt, eine Statusvariable zu überprüfen, und mein Programm würde vor der Wartezeit signalisieren. Dies ist der gesamte Punkt der Warte-/Signalfunktionen. Warten auf einige mutexgeschützte Änderungen im Speicherzustand. –