2012-06-19 12 views
19

Me pregunto si los métodos de extensión de Linq son atómicos? ¿O necesito lock algún objeto IEnumerable utilizado entre subprocesos, antes de cualquier tipo de iteración?¿Los métodos de IEnumerable Linq son seguros para subprocesos?

¿Decir que la variable como volatile tiene algún efecto en esto?

En resumen, ¿cuál de las siguientes opciones es la mejor operación segura para hilos?

1- Sin ningún tipo de cerraduras:

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

2- incluyendo las declaraciones de bloqueo:

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

3- Declarar variable como volátil:

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

No son seguros para subprocesos. Ver http://stackoverflow.com/questions/9995266/how-to-create-a-thread-safe-generic-list – stuartd

Respuesta

20

La interfaz IEnumerable<T> no es segura para subprocesos. Consulte la documentación en http://msdn.microsoft.com/en-us/library/s793z9y2.aspx, que dice:

Un enumerador sigue siendo válido siempre que la colección permanezca sin cambios. Si se realizan cambios en la colección, como agregar, modificar o eliminar elementos, el enumerador queda irrevocablemente invalidado y su comportamiento no está definido.

El enumerador no tiene acceso exclusivo a la colección; por lo tanto, enumerar a través de una colección no es intrínsecamente un procedimiento seguro para subprocesos. Para garantizar la seguridad del subproceso durante la enumeración, puede bloquear la recopilación durante toda la enumeración. Para permitir que la colección sea accedida por múltiples hilos para lectura y escritura, debe implementar su propia sincronización.

Linq no cambia nada de esto.

El bloqueo obviamente se puede usar para sincronizar el acceso a los objetos. Sin embargo, debe bloquear el objeto en cualquier lugar al que acceda, no solo al iterar sobre él.

Declarar que la colección es volátil no tendrá ningún efecto positivo. Solo da como resultado una barrera de memoria antes de una lectura y después de una escritura de la referencia a la colección. No sincroniza la lectura o escritura de la colección.

7

En resumen, no son seguros para subprocesos como se mencionó anteriormente.

Sin embargo, eso no significa que deba bloquear antes de "cada tipo de iteración".

Necesita sincronizar todas las operaciones que cambian la colección (agregar, modificar o eliminar elementos) con otras operaciones que (agregar, modificar, eliminar elementos o leer elementos).

Si solo está realizando operaciones de lectura en la colección al mismo tiempo, no es necesario el bloqueo. (Así que ejecutar comandos LINQ como Average, Contains, ElementAtOrDefault todos juntos sería bueno)

Si los elementos en la colección son de longitud de palabra de máquina, como Int en la mayoría de las computadoras de 32 bits, entonces cambiar el valor de ese elemento ya se realiza atómicamente.En este caso, no agregue ni elimine elementos de la colección sin bloquearlos, pero modificar los valores puede ser correcto, si puede tratar con algo de no determinismo en su diseño.

Por último, puede considerar el bloqueo fino en elementos individuales o secciones de la colección, en lugar de bloquear toda la colección.

Cuestiones relacionadas