2010-04-12 25 views
7

Ho una classe che contiene un campo booleano come questo:multithreading e booleani

public class MyClass 
{ 
    private bool boolVal; 
    public bool BoolVal 
    { 
     get { return boolVal; } 
     set { boolVal = value; } 
    } 
} 

Il campo possono essere letti e scritti da tanti fili utilizzando la proprietà. La mia domanda è se dovrei recintare il getter e setter con una dichiarazione di blocco? O dovrei semplicemente usare la parola chiave volatile e salvare il blocco? O dovrei assolutamente ignorare il multithreading da quando ho ottenuto e impostato i valori booleani atomici?

saluti,

risposta

9

Ci sono diversi problemi qui.

Il semplice prima. Sì, leggere e scrivere una variabile booleana è un'operazione atomica. (precisazione: Quello che voglio dire è che la lettura e scrittura da soli sono operazioni atomiche per booleani, non leggere e scrittura, che sarà ovviamente generare due operazioni, che insieme non saranno atomica)

Tuttavia, a meno che non si adottino ulteriori passaggi, il compilatore potrebbe ottimizzare tali operazioni di lettura e scrittura o spostare le operazioni in giro, il che potrebbe far funzionare il codice in modo diverso da quello che si intende.

Marcatura il campo come volatile significa che le operazioni non saranno ottimizzate di distanza, la direttiva in pratica dice che il compilatore non deve mai assumere il valore in questo campo è lo stesso di quello precedente, anche se è appena letto nel istruzioni precedenti.

Tuttavia, su macchine multicore e multicpu, diversi core e cpu potrebbero avere un valore diverso per il campo nella loro cache, e quindi aggiungere una clausola lock { } o qualsiasi altra cosa che costringa una barriera di memoria. Ciò assicurerà che il valore del campo sia coerente tra i core. Inoltre, le letture e le scritture non si sposteranno oltre una barriera di memoria nel codice, il che significa che hai la prevedibilità in cui si verificano le operazioni.

Quindi, se sospettate, o sapete, che questo campo verrà scritto e letto da più thread, aggiungo sicuramente il blocco e il volatile al mix.

Nota che non sono esperto di multithreading, sono in grado di tenere il mio, ma di solito programma in modo difensivo. Potrebbe (presumibilmente è altamente probabile) che tu possa implementare qualcosa che non usa un lock (ci sono molti costrutti lock-free), ma purtroppo non sono abbastanza esperto in questo argomento per gestire queste cose. Pertanto, il mio consiglio è di aggiungere sia una clausola lock sia una direttiva volatile.

+0

"leggere e scrivere una variabile booleana è un'operazione atomica". ... questo non è vero. Qualcosa di semplice come "booleano a = b" genera 2 istruzioni JVM. – sgp15

+0

Mi dispiace, * leggere * e * scrivere * operazioni da soli sono operazioni atomiche per i booleani, leggere e poi scrivere, è due. Questo è vero per **. NET ** e Java. –

2

volatili da sola non è sufficiente e serve per uno scopo diverso, blocco dovrebbe andare bene, ma alla fine dipende se qualcuno sta per impostare boolVal in MyClass iself, chi lo sa, potrebbe essere un filo dell'operaio che gira lì dentro. Dipende anche e come stai usando boolVal internamente. Potresti aver bisogno di protezione anche altrove. Se mi chiedi, se non sei MORTO Sicuramente userai MyClass in più di un thread, quindi non vale nemmeno la pena di pensarci.

P.S. potresti anche leggere this section