2010-09-09 14 views
15

Aggiornamento: Ho appena imbattuto in questo in Eric Lippert's answer-another question (che sta citando la specifica):Sta leggendo un doppio non thread-safe?

Legge e scrive di altri tipi, compreso lunga, ulong, doppio, e decimale, come pure come tipi definiti dall'utente , non è garantito l'atomico .

OK, quindi la lettura di un double è non atomica. Ciò significa che il valore potrebbe essere modificato in lettura centrale, giusto? Quindi, come si legge un valore double atomicamente?


ho notato c'è un metodo per Interlocked.Readlong valori. Questo ha senso per me, poiché la lettura di un valore a 64 bit richiede due passaggi e pertanto è soggetta alle condizioni di gara, proprio come ogni altra azione non atomica.

Ma non ci sono valori Interlocked.Read per double, anche se System.Double è un valore a 64 bit.

sto vedendo un po 'strani comportamenti nel mio programma in cui la mia interfaccia grafica, che mostra una double in una casella di testo mentre quella double viene anche aggiornato frequentemente da altri thread, sta mostrando il valore corretto (in prossimità di 200,0) più del tempo e quindi a caso mostrando un valore errato (come -0.08) occasionalmente.

Forse questo è un problema di threading, o forse è qualcos'altro. Ma prima volevo restringere le possibilità. Quindi: sta leggendo un double thread-safe?

+0

Ricorda che anche se la lettura è atomica, non ti aiuterà se la scrittura non lo è. – nos

+0

@nos: giusto. Ma è strano perché la classe 'Interlocked' * fornisce * operazioni di scrittura atomica:' Exchange' e 'CompareExchange' accettano entrambi argomenti' double'. –

+3

@Dan, in risposta alla domanda di follow-up nella modifica, vedere la risposta di Jon Skeet [risposta a un'altra domanda qui] (http://stackoverflow.com/questions/531759/c-volatile-double/531772#531772), in cui suggerisce di usare 'BitConverter' per spostarsi tra long e double (in congiunzione con' Interlocked.Read'). –

risposta

10

Il solito modo: controllare l'accesso con un lucchetto.

+0

Fondamentalmente, questa sembra essere la risposta più sensata (e arrivata prima, anche se Eric è anche abbastanza informativo). Sono affascinato dalla possibilità di altri approcci più avventurosi; ma inseguirò quelli del mio tempo e accetto che questa è la cosa ragionevole da fare in quasi tutti i casi. –

16

sta leggendo una doppia discussione sicura?

No. Come le specifiche dice

legge e scrive di altri tipi, tra cui lungo, ulong, doppio, e decimali, così come i tipi definiti dall'utente, non sono garantiti per essere atomica.

In movimento.

Ciò significa che il valore potrebbe essere modificato in lettura centrale, giusto?

Sì.

Quindi come si legge un doppio valore atomicamente?

È possibile bloccare tutti gli accessi alla variabile mutabile.

E una domanda non ha chiesto, ma spesso viene chiesto come follow-up alle tue domande:

Vuol fare un campo "volatile" make legge/scrive di esso atomica?

No. Non è legale creare un campo volatile di tipo double.

2

Il CLR promette solo un allineamento variabile di 4. Ciò significa che è del tutto possibile per un lungo o doppio per scavalcare i limiti di una cache-line della CPU. Ciò rende la lettura garantita non atomica.

È anche un problema di perforazione abbastanza serio, la lettura di una variabile mal allineata è oltre 3 volte più lenta. Niente di ciò che puoi fare al di là di puntatori hacker.

+1

Se c'è un errore di cache nell'istruzione x86 fld, non sono sicuro che la CPU consentirà un carico parziale al registro FPU. La mia ipotesi è che la CPU stessa eseguirà alcuni collegamenti per preservare l'atomicità delle operazioni della FPU. Non ho trovato documenti Intel per dimostrare o smentire questo. Tuttavia, anche se le CPU Intel fanno questo, altri no. –

5

Utilizzare Interlocked.Exchange O Interlocked.CompareExchange per la lettura atomica come questa.

Interlocked.Exchange(ref somevariable, somevariable)

Si restituisce valore originale.

Se si desidera evitare di scrivere utilizzare compareExchange.

Interlocked.CompareExchange(ref somevariable, somevalue, somevalue);

Questo sostituirà la variabile con il secondo argomento se è uguale al terzo argomento, e riportare il valore originale. Utilizzando lo stesso valore (ad es. Zero) in entrambi i punti garantisce che il valore della variabile non venga modificato.

Problemi correlati