2012-10-13 9 views
7

considerare le seguenti due alternative di ottenere il numero maggiore tra currentPrice e 100 ...L'operatore ternario (? :) thread safe in C#?

int price = currentPrice > 100 ? currentPrice : 100 

int price = Math.Max(currentPrice, 100) 

ho sollevato questa domanda perché stavo pensando a un contesto in cui la variabile currentPrice potrebbe essere modificato da altri thread.

Nel primo caso ... potrebbe price ottenere un valore inferiore a 100?

sto pensando a quanto segue:

if (currentPrice > 100) { 
    //currentPrice is edited here. 
    price = currentPrice; 
} 

risposta

8

Non è threadsafe.

?: è solo scorciatoia per il normale if, in modo che il campione if è equivalente a una ? - è possibile ottenere il prezzo più basso di 100, se non v'è alcun blocco al di fuori di questo codice.

+0

Risposta contraria in pochi minuti? : D – dotNETbeginner

+0

@dotNETbeginner :) Buona osservazione. quando ho letto la mia prima risposta, volevo darmi anche io -10. –

3

In teoria, currentPrice viene letto due volte. Una volta per il confronto, una volta per l'assegnazione.

In pratica, il compilatore può memorizzare nella cache l'accesso alla variabile. Non so su C#, ma in C++ su x86:

MOV AX, [currentPrice] 
MOV BX, 100 ;cache the immediate 
CMP AX, BX 
JLE $1  ;if(currentPrice > 100){ 
MOV AX, BX 
$1:   ;} 
MOV [BP+price], AX ;price is on the stack. 

Lo stesso carico una volta l'ottimizzazione avviene in Java bytecode a meno currentPrice viene dichiarata volatile.

Quindi, in teoria, può succedere. In pratica, sulla maggior parte delle piattaforme, non lo sarà, ma non puoi contare su questo.

3

Non uno specialista in C#, ma anche var ++ non è thread save, poiché può essere tradotto da lettura/scrittura dal registro in assembly.

L'operatore ternario è molto più complicato. Ha 3 parti, mentre ogni parte può essere infinitamente grande (ad esempio chiamata ad alcune funzioni). Pertanto, è abbastanza facile concludere che l'operatore ternario non è thread-safe.

+1

+1; Temo che x86 non ti permetta di 'INCmentare una posizione di memoria, quindi sarà_will_ essere tradotto come una mossa nel registro/incrementa/passa alla combo di memoria. –

1

Come affermato da altri, potrebbe essere memorizzato nella cache ma la lingua non lo richiede.

È possibile utilizzare Interlocked.CompareExchange se sono necessarie assegnazioni thread-safe prive di lock. Ma dato l'esempio, opterei per una strategia di bloccaggio a grana più grossa.