2009-03-09 11 views
9

mi sono imbattuto in questo paragrafo interessante nel Boost thread documentation oggi:sblocco spurie in filo di spinta

void wait(boost::unique_lock<boost::mutex>& lock) 

...

Effetti: lock.unlock Atomicamente call() e blocca il thread corrente . Il thread verrà sbloccato quando viene notificato da una chiamata a questo-> notify_one() o this-> notify_all() o spuratamente. Quando il thread è sbloccato (per il motivo ), il blocco è riacquisito richiamando lock.lock() prima che la chiamata attenda i ritorni. Il blocco viene riacquisito anche richiamando lock.lock() se la funzione termina con un'eccezione.

Quindi quello che mi interessa è il significato della parola "spurio". Perché il thread dovrebbe essere sbloccato per motivi spuri? Cosa si può fare per risolvere questo?

risposta

10

This article by Anthony Williams è particolarmente dettagliato.

scie spuri non possono essere previsti: sono essenzialmente casuale dal punto di vista dell'utente . Tuttavia, si verificano in genere quando la libreria di thread non può garantire in modo affidabile che una thread in attesa di non manchi una notifica. Dal momento che una notifica mancata rende la variabile di condizione inutile, la libreria di thread riattiva la thread dall'attesa piuttosto che prendere il rischio .

Egli sottolinea inoltre che non si deve usare le timed_wait sovraccarichi che prendono una durata, e si dovrebbe in genere utilizzare le versioni che prendono un predicato

Ecco bug del principiante, e uno questo è facilmente superato con una semplice regola : controlla sempre il tuo predicato in un ciclo in attesa con una variabile di condizione . Il bug più insidioso arriva da timed_wait().

This article by Vladimir Prus è anche interessante.

Ma perché abbiamo bisogno del ciclo while, non possiamo scrivere:

if (!something_happened) 
    c.wait(m); 

Non possiamo. E il motivo killer è che "aspetta" può restituire senza alcuna chiamata "notifica". Si chiama wakeful spurie ed è esplicitamente consentito da POSIX. In sostanza, il ritorno da "wait" solo indica che i dati condivisi potrebbero essere modificati, in modo che i dati debbano essere valutati nuovamente .

Ok, quindi perché non è stato ancora risolto? La prima ragione è che nessuno vuole che risolva. La chiamata di "attesa" in a ciclo è molto desiderata per diversi altri motivi. Ma questi motivi richiedono spiegazioni, mentre il falso wakeup è un martello che può essere applicato a in qualsiasi studente del primo anno senza fallito.

+0

Sembra che abbiamo trovato le stesse pagine, che non è del tutto inaspettato :) –

+1

sì, questo è una sorta di riassunto della mia ricerca oggi quando ho capito la causa del bug orribile che ho stava soffrendo La documentazione di boost potrebbe essere più chiara su questo punto. –

+1

Ho riscontrato un aumento dell'intero sistema per l'attesa e la notifica, specialmente in boost :: interprocess, è molto frustrante. Lo userei solo se ne hai bisogno per essere multipiattaforma e fatto ora. –

2

This blog post fornisce un motivo per Linux, in termini di chiamata di sistema futex restituita quando un segnale viene consegnato a un processo. Sfortunatamente non spiega nient'altro (e anzi chiede maggiori informazioni).

Il Wikipedia entry on spurious wakeups (che sembra essere un concetto di posix-wide, btw, non limitato a boost) potrebbe interessarti anche tu.

+0

Hmm si, questa non è una risposta soddisfacente dato che si applica solo a una piattaforma, anche se credo che sia davvero difficile farlo funzionare correttamente su Linux, quindi potrebbe essere un valido motivo per documentare wakeful spurie –