Sblocco spurio nel thread boost
-
05-07-2019 - |
Domanda
Mi sono imbattuto in questo interessante paragrafo nel Aumenta la documentazione del thread oggi:
void wait(boost::unique_lock<boost::mutex>& lock)
...
Effetti: chiama atomicamente lock.unlock () e blocca il thread corrente. Il il thread verrà sbloccato quando notificato da a chiama a this- > notification_one () o this- > notification_all () o spuratamente . Quando il thread è sbloccato (per qualunque sia la ragione), la serratura è riacquistato invocando lock.lock () prima che la chiamata in attesa ritorni. Il il blocco viene inoltre riattivato invocando lock.lock () se la funzione termina con un'eccezione.
Quindi quello che mi interessa è il significato della parola "spurdamente". Perché il thread dovrebbe essere sbloccato per motivi spuri? Cosa si può fare per risolvere questo problema?
Soluzione
Questo articolo di Anthony Williams è particolarmente dettagliato .
I risvegli spuri non possono essere previsti: sono essenzialmente casuali dal punto di vista dell'utente. Tuttavia, loro si verificano comunemente quando la libreria di thread non può garantire in modo affidabile un'attesa il thread non perderà una notifica. Dal momento che una notifica persa sarebbe rendere la variabile di condizione inutile, la libreria di thread riattiva il thread dalla sua attesa piuttosto che prendere il rischio.
Sottolinea inoltre che non dovresti usare i sovraccarichi timed_wait
che richiedono una durata e generalmente dovresti usare le versioni che accettano un predicato
Questo è il bug del principiante, e uno che è facilmente superato con un semplice regola: controlla sempre il tuo predicato in a loop quando si attende con una condizione variabile. Il bug più insidioso arriva da timed_wait ().
Anche questo articolo di Vladimir Prus è interessante.
Ma perché abbiamo bisogno del ciclo while, non possiamo scrivere:
if (!something_happened)
c.wait(m);
Non possiamo. E la ragione killer è che l'attesa può restituire senza alcuna chiamata di "notifica". Questo si chiama risveglio spurio ed è esplicitamente consentito da POSIX. In sostanza, ritorna solo da "aspetta" indica che i dati condivisi potrebbero sono cambiati, quindi i dati devono essere valutato di nuovo.
Va ??bene, quindi perché questo non è stato ancora risolto? La prima ragione è che nessuno vuole per risolverlo. Avvolgimento della chiamata per "attendere" un loop è molto desiderato per diversi altri motivi. Ma quei motivi richiede una spiegazione, sebbene falsa wakeup è un martello che può essere applicato a qualsiasi studente del primo anno senza fallire.
Altri suggerimenti
Questo post sul blog fornisce una ragione per Linux, in termini della chiamata di sistema futex
che ritorna quando un segnale viene inviato a un processo. Purtroppo non spiega nient'altro (e anzi chiede maggiori informazioni).
La la voce di Wikipedia sui risvegli spuri (che sembra essere un concetto ampio, tra l'altro, non solo per aumentare) potrebbe interessarti anche tu.