2015-07-27 12 views
8

Sto cercando di impostare i flag di bit in una variabile condivisa all'interno di un'applicazione .NET multithread, ma non è stato possibile trovare un parallelo con la funzione nativa InterlockedOr nella classe gestita Interlocked . Mi è venuta in mente il seguente codice per l'esecuzione di un | = assegnazione, ma la possibilità teorica di un ciclo infinito mi sta facendo a disagio:Implementazione di un'operazione bit per bit utilizzando la classe Interlocked in .NET

long currentValue; 
long updatedValue; 

do 
{ 
    // Spin until successful update. Value must be read using Interlocked.Read() 
    // to be truly atomic on 32 bit systems (see MSDN). 
    currentFlags = Interlocked.Read(ref _currentFlags); 
    updatedValue = currentFlags | flag; 
} while (currentFlags != Interlocked.CompareExchange(ref _currentFlags, updatedValue, currentFlags)); 

questo può essere implementato in un modo più sicuro utilizzando solo le funzioni integrate in la classe Interlocked? Vorrei evitare una soluzione che implichi un blocco esplicito, se possibile.

+1

Mentre esiste la possibilità di un ciclo infinito utilizzando 'CompareExchange', è così improbabile che venga rilevato che può essere ignorato. Il .NET Framework utilizza questa tecnica molto ampiamente, anche in tutte le sue collezioni concorrenti al fine di ottenere la sincronizzazione senza blocchi. –

+0

Si otterrebbe un ciclo infinito solo se qualche altro thread ripristina contemporaneamente il flag a zero ed è abbastanza agile da battere il thread su di esso ogni volta, per un numero infinito di tentativi. Se ciò accade, hai grossi problemi da risolvere, capendo perché il thread "agile" fa quello che fa. Penso che la tua soluzione sia all'altezza di 'Interlocked'. – dasblinkenlight

risposta

1

Supponiamo (queste restrizioni non sono fondamentali, solo per semplificare l'illustrazione) che

  • all'inizio currentFlags è 0,
  • abbiamo impostato al massimo una sola bandiera in un unico passaggio,
  • facciamo non toccare il bit del segno.

Si noti che se impostiamo po k-1 in currentFlagsvolta, potremmo sostituire or con + 1L << k. Quindi possiamo usare un array di supporto set per ricordare quali bit sono già impostati, e fare Interlocked.Add se necessario.

long currentFlags = 0; 
int[] set = new int[sizeof(long) * 8]; 

.... 

int k = ...; // bit to set 
if(Interlocked.Exchange(ref set[k], 1) == 0) 
    Interlocked.Add(ref currentFlags, 1L << k);