2009-10-06 17 views
31

Ho una classe che ha uno stato (un enum semplice) a cui si accede da due thread. Per cambiare stato uso un mutex (boost :: mutex). È sicuro controllare lo stato (ad esempio confrontare lo stato_ == ESTABLISHED) o devo usare il mutex anche in questo caso? In altre parole ho bisogno del mutex quando voglio solo leggere una variabile che potrebbe essere scritta contemporaneamente da un altro thread?Ho bisogno di un mutex per la lettura?

risposta

3

Sì. Se il thread a legge una variabile mentre il thread b lo sta scrivendo, puoi leggere un valore non definito. Le operazioni di lettura e scrittura non sono atomiche, specialmente su un sistema multiprocessore.

+0

mentre un thread di scrittura fa (fetch-> write-> store) non vedo quando nel mezzo di quelli un lettore recupera un valore indefinito, precedente o successivo, ma mai indefinito. –

+0

Prendere in considerazione i valori enum che vengono letti in un'unica istruzione. –

+1

@Arkaitz: probabilmente non era definita la parola giusta. Ma le architetture CPU/memoria diventano sempre più complesse con livelli aggiunti di cache, latenze aumentate, ecc. La risposta è semplice: Say No! per condividere i dati senza bloccare. Anche gli esperti commettono molti errori in quest'area. – sellibitze

0

In generale non lo si fa, se la variabile è dichiarata con "volatile". E SOLO se è una singola variabile, altrimenti dovresti fare molta attenzione alle possibili razze.

+0

Perché pensi che le cose volatili? – jalf

+1

@jalf: volatile dice al compilatore di non eseguire ottimizzazioni che potrebbero far sì che il codice veda una copia obsoleta della variabile. –

+2

Ma la domanda non riguardava copie stantie. Anche se la variabile non è volatile, verrà scritta prima o poi. Sarà atomico indipendentemente dalla volatilità, e volatile non impedisce il riordino di carico/negozio. Così volatile non ti compra davvero niente in questo caso. Non risolve il problema che deve essere risolto, e risolve quello che sarebbe stato risolto comunque. – jalf

0

L'accesso all'enum (lettura o scrittura) deve essere protetto.

Un'altra cosa: Se il conflitto di thread è inferiore ei thread appartengono allo stesso processo, la sezione critica sarebbe migliore di mutex.

8

Hai due thread, si scambiano informazioni, sì, hai bisogno di un mutex e probabilmente hai anche bisogno di un'attesa condizionale.

Nel tuo esempio (confronta state_ == ESTABLISHED) indica che il thread n. 2 è in attesa del thread n. 1 per iniziare una connessione/stato. Senza un mutex o condizionali/eventi, il thread # 2 deve interrogare continuamente lo stato.

I thread vengono utilizzati per aumentare le prestazioni (o migliorare la reattività), il polling di solito determina una riduzione delle prestazioni, consumando molta CPU o introducendo latenza a causa dell'intervallo di polling.

+0

+1 per suggerire variabili condizionali. Dai suoni di esso ha un thread che ha bisogno di rispondere a un cambiamento di stato da un altro cambiamento. Se questo è il caso, le variabili condizionali sono molto più appropriate. – Falaina

+0

@Ermelli abbiamo ancora bisogno di mutex se vogliamo comunque usare il ciclo di attesa occupato (perché il ciclo potrebbe fare qualcos'altro nel frattempo) – Nick

0

in realtà, non vi è alcun motivo per bloccare l'accesso all'oggetto per la lettura. vuoi solo bloccarlo mentre ci scrivi. questo è esattamente ciò che un lucchetto di lettore-scrittore è. non blocca l'oggetto finché non ci sono operazioni di scrittura. migliora le prestazioni e previene i deadlock. consultare i seguenti link per spiegazioni più elaborate:

wikipedia codeproject

12

Dipende.

Il linguaggio C++ non dice nulla su thread o atomicità.

Ma su più CPU moderna, la lettura di un intero è un'operazione atomica, il che significa che si leggerà sempre un valore coerente, anche senza un mutex.

Tuttavia, senza un mutex, o qualche altra forma di sincronizzazione, il compilatore e CPU sono liberi di riordinare lettura e scrittura, in modo da qualcosa di più complesso, tutto ciò che coinvolge l'accesso a più variabili, è ancora pericoloso nel caso generale.

Supponendo che il filo scrittore aggiorna alcuni dati, e quindi imposta un flag intero per informare altri fili che sono disponibili i dati, questo potrebbe essere riordinate in modo che il flag è impostato prima aggiornamento dei dati. A meno che non si usi un mutex o un'altra forma di barriera di memoria.

Quindi, se si desidera un comportamento corretto, non è necessario un mutex come tale, e non è un problema se un altro thread scrive sulla variabile durante la lettura. Sarà atomico a meno che non si stia lavorando su una CPU molto insolita.Ma è necessario che do richieda una barriera di memoria di qualche tipo per impedire il riordino nel compilatore o nella CPU.

+0

A meno che non si specifichi una volatile, la lettura (o la scrittura) potrebbe * mai * essere eseguita. Prima o poi non è abbastanza buono. – EFraim

+3

Ma anche con la volatile, la CPU o il compilatore potrebbero riordinare le scritture, rendendole prive di significato. La soluzione corretta è una barriera di memoria, e quindi volatile è solo una deoptimizzazione inutile. – jalf

+0

@jalf: No, se è necessaria solo una singola bandiera. Leggi di nuovo la domanda. – EFraim

Problemi correlati