2012-06-19 2 views
19

Mi chiedo se i metodi di estensione Linq siano atomici? O ho bisogno di lock qualsiasi oggetto IEnumerable utilizzato nei thread, prima di qualsiasi tipo di iterazione?I metodi IEnumerable Linq sono thread-safe?

La dichiarazione della variabile volatile ha qualche effetto su questo?

Per riassumere, quale delle seguenti è la migliore, thread-safe, operazione?

1- Senza alcun blocco:

IEnumerable<T> _objs = //... 
var foo = _objs.FirstOrDefault(t => // some condition 

2- Compresi istruzioni lock:

IEnumerable<T> _objs = //... 
lock(_objs) 
{ 
    var foo = _objs.FirstOrDefault(t => // some condition 
} 

3- Dichiarazione variabile come volatile:

volatile IEnumerable<T> _objs = //... 
var foo = _objs.FirstOrDefault(t => // some condition 
+0

Non sono thread-safe. Vedi http://stackoverflow.com/questions/9995266/how-to-create-a-thread-safe-generic-list – stuartd

risposta

20

L'interfaccia IEnumerable<T> non è thread-safe. Vedere la documentazione su http://msdn.microsoft.com/en-us/library/s793z9y2.aspx, che indica:

Un enumeratore rimane valido fino a quando la raccolta rimane invariata. Se vengono apportate modifiche alla raccolta, come l'aggiunta, la modifica o l'eliminazione di elementi, l'enumeratore viene irrimediabilmente invalidato e il suo comportamento non è definito.

L'enumeratore non ha accesso esclusivo alla raccolta; pertanto, l'enumerazione tramite una raccolta non è intrinsecamente una procedura thread-safe. Per garantire la sicurezza dei thread durante l'enumerazione, è possibile bloccare la raccolta durante l'intera enumerazione. Per consentire l'accesso alla raccolta da più thread per la lettura e la scrittura, è necessario implementare la propria sincronizzazione.

Linq non cambia nulla.

Il blocco può ovviamente essere utilizzato per sincronizzare l'accesso agli oggetti. Devi bloccare l'oggetto ovunque ti acceda, non solo durante l'iterazione.

Dichiarare la raccolta come volatile non avrà alcun effetto positivo. Risulta solo una barriera di memoria prima di una lettura e dopo una scrittura del riferimento alla raccolta. Non sincronizza la lettura o la scrittura della collezione.

7

In breve, non sono thread-safe come sopra menzionato.

Tuttavia, ciò non significa che è necessario bloccare prima di "ogni tipo di iterazione".

È necessario sincronizzare tutte le operazioni che modificano la raccolta (aggiungi, modifica o rimuovi elementi) con altre operazioni che (aggiungi, modifica, rimuovi elementi o leggi elementi).

Se si stanno eseguendo contemporaneamente operazioni di lettura sulla raccolta, non è necessario alcun blocco. (quindi eseguire comandi LINQ come Media, Contains, ElementAtOrDefault tutti insieme andrebbe bene)

Se gli elementi della raccolta sono di lunghezza parola macchina, ad esempio Int sulla maggior parte dei computer a 32 bit, quindi cambiano il valore di quell'elemento è già eseguito atomicamente.In questo caso non aggiungere o rimuovere elementi dalla raccolta senza bloccarli, ma la modifica dei valori potrebbe andar bene, se è possibile gestire alcuni aspetti non deterministici nella progettazione.

Infine, è possibile considerare il blocco a grana fine su singoli elementi o sezioni della raccolta, piuttosto che bloccare l'intera raccolta.