2009-07-16 14 views
44

Sto imparando pthread e condizioni di attesa. Per quanto posso dire una tipica thread in attesa è come questo:Pthread e condizioni di attesa

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

Quello che non riesco a capire è perché la linea while(!condition) è necessario, anche se io uso pthread_cond_signal() per riattivare il thread.

posso capire che se uso pthread_cond_broadcast() ho bisogno di testare condizione, perché mi sveglio tutte thread in attesa e uno di essi può rendere la condizione falsa nuovamente prima di sbloccare il mutex (e quindi trasferendo esecuzione all'altro risvegliato thread che non dovrebbe essere eseguito in quel punto). Ma se uso pthread_cond_signal() Mi sveglio solo un thread quindi la condizione deve essere vera. Quindi il codice potrebbe essere il seguente:

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

Ho letto qualcosa sui segnali spuri che possono accadere. Questa è (e solo questa) la ragione? Perché dovrei avere dei nomi falsi? O c'è qualcos'altro che non capisco?

Suppongo che il codice di segnale è simile a questo:

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

risposta

43

La vera ragione per cui si deve mettere pthread_cond_wait in un ciclo while non è a causa di una sveglia spuria. Anche se la variabile di condizione non ha una sveglia spuria, è comunque necessario che il ciclo riceva un tipo di errore comune. Perché? Considerate ciò che può accadere se più thread attendono la stessa condizione:

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> 

Il problema qui è che il filo deve rilasciare il mutex prima di attendere, potenzialmente permettendo un altro thread per 'rubare' qualunque cosa filo stava aspettando. A meno che non sia garantito che solo un thread può attendere su quella condizione, non è corretto presumere che la condizione sia valida quando un thread si riattiva.

+1

esattamente. up-votato. questo dovrebbe ottenere più attenzione rispetto alla risposta accettata. –

15

Supponiamo non selezioni la condizione. Poi di solito non è possibile evitare il seguente brutta cosa accade (almeno, non si può evitare in una riga di codice):

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

Naturalmente il vostro esempio secondo codice potrebbe evitare questo facendo:

Quindi sarebbe sicuramente il caso che se al massimo ci fosse un solo ricevitore e se cond_signal fosse l'unica cosa che potesse svegliarlo, allora si sarebbe sempre svegliato solo quando la condizione era impostata e quindi non avrebbe bisogno di un ciclo. nn spiega perché il secondo "se" non è vero.

+0

Vedo, quindi un "se" è necessario a causa di un motivo logico (attesa infinita), ma un po 'di tempo è effettivamente necessario a causa di problemi di implementazione (segnali spuri). – Emiliano

+0

Sì, quando ho usato per la prima volta la libreria pthreads ho fatto la stessa domanda. Ho omesso di controllare una variabile di stato e il mio programma avrebbe segnalato prima che si verificasse l'attesa. Questo è l'intero punto delle funzioni di attesa/segnale. Attendere e segnalare alcuni mutex protetti in stato di memoria. –