2009-12-22 26 views
15

Estoy tratando de obtener una visión general de la teoría de la seguridad del hilo detrás de las colecciones en C#.¿Por qué no hay colecciones concurrentes en C#?

¿Por qué no hay colecciones simultáneas como las hay en Java? (java docs). Algunas colecciones aparecen hilo de seguridad, pero no es claro para mí lo que la posición es por ejemplo con respecto a:

  • operaciones compuestas,
  • seguridad del uso de iteradores,
  • operaciones de escritura

¡No quiero reinventar la rueda! (No soy un gurú de multi-threading y definitivamente no estoy subestimando lo difícil que sería de todos modos).

Espero que la comunidad pueda ayudar.

+0

Gran respuesta - Voy a dejar esto "sin respuesta" por un tiempo breve para mantenerlo en el radar. Si alguien tiene más enlaces a artículos sobre pre o post .Net 4.0 estado de juego sobre este tema, inclúyalo. Gracias a todos. – Andrew

Respuesta

28

.NET ha tenido el soporte de concurrencia relativamente "bajo nivel" hasta ahora - pero .NET 4.0 presenta el espacio de nombres System.Collections.Concurrent que contiene varias colecciones que son seguros y útiles.

La respuesta de Andrew es completamente correcta en términos de cómo tratar con colecciones anteriores a .NET 4.0, por supuesto, y para la mayoría usa para bloquear correctamente cuando accedo a una colección compartida "normal". Las colecciones concurrentes, sin embargo, hacen que sea fácil de usar a/cola consumidor productor, etc.

+0

+1 gracias Jon. Supongo que de esa manera .net no arrulla a las personas con una falsa sensación de seguridad. Veré los regalitos de .Net 4.0. - Andrew – Andrew

+0

+1 Agradable, se olvidó de todo eso :) –

19

C# ofrece varias formas de trabajar con colecciones en varios subprocesos. Para un buen relato de estas técnicas Yo recomendaría que comience con Collections and Synchronization (Thread Safety):

Por defecto, las clases son Colecciones generalmente no seguro para subprocesos. Múltiples lectores pueden leer la colección con confianza ; sin embargo, cualquier modificación a la colección produce resultados indefinidos de para todos los hilos que acceden a la colección , incluidos los hilos del lector.

clases Collections se pueden hacer hilo segura utilizando cualquiera de los métodos siguientes:

  • crear un contenedor seguro para subprocesos usando el método sincronizado, y acceder a la colección exclusivamente a través de esa envoltura.
  • Si la clase no tiene un método Sincronizado, deriva de la clase e implementa un método Sincronizado utilizando la propiedad SyncRoot.
  • Utilice un mecanismo de bloqueo, como la instrucción de bloqueo en C# (SyncLock en Visual Basic), en la propiedad SyncRoot al acceder a la colección .
+0

+1 ¡eso fue rápido! - Se parece un poco a Collections.synchronizedList de Java. Voy a verificar ese enlace. Gracias – Andrew

+4

Y mira también aquí: http://blogs.msdn.com/ericlippert/archive/2008/01/21/immutability-in-c-part-nine-academic-plus-my-avl-tree-implementation.aspx donde Eric Lippert discute colecciones inmutables con cierta profundidad, específicamente con respecto al acceso concurrente. –

+0

Gracias Jeremy no había cruzado este blog (ahora suscrito) hay algún material excelente bajo la etiqueta de inmutabilidad. – Andrew

6

Como se mencionó Jon Skeet, ahora hay "seguros hilo" colecciones en el espacio de nombres System.Collections.Concurrent en .NET 4.

Una de las razones por las que no existen colecciones concurrentes (al menos mi suposición) en anteriores.Las versiones de NET Framework es que es muy difícil garantizar la seguridad del subproceso, incluso con una recopilación simultánea.

(Esto no es del todo cierto ya que algunas colecciones ofrecen un método sincronizado para devolver una colección segura hilo de una recogida segura pero sin hilos así que hay algunas colecciones seguras hilo ...)

Por ejemplo suponer que uno tiene un diccionario seguro para subprocesos: si uno solo desea una inserción si la clave no existe, primero se consultará la colección para ver si existe la clave, luego se haría una inserción si la clave no existe. Estas dos operaciones no son seguras para hilos, sin embargo, entre la consulta de ContainsKey y la operación Agregar otro hilo podría haber hecho una inserción de esa clave por lo que hay una condición de carrera.

En otras palabras, las operaciones de la colección son seguras para hilos, pero su uso no es necesariamente. En este caso, uno debería volver a las técnicas de bloqueo tradicionales (mutex/monitor/semáforo ...) para lograr la seguridad de subprocesos, por lo que la recopilación simultánea no le ha comprado nada en términos de seguridad de subprocesos múltiples (pero probablemente sea peor para el rendimiento) .

+0

Estaba pensando en la misma línea. El problema de poner-si-ausente donde podría terminar con 2 objetos en su colección donde antes no había ninguno. Gracias +1. – Andrew

+0

@saret: ¿Qué tan difícil es, en realidad, proporcionar las funciones que se necesitan para un verdadero uso seguro de subprocesos? Yo pensaría que si el diccionario no necesita tener valores de "Nada", todo se puede hacer con un enumerador, una propiedad de recuento de cambios largos y un método que funciona de forma análoga a Threading.Interlocked.CompareExchange. Agregar valores "Nothing" crea un poco más de complejidad, pero no demasiado. – supercat

+0

@supercat, una forma posiblemente mejor es ofrecer métodos en la colección que funcionen dentro de un bloqueo (como ejecutar acción/func dentro de un bloqueo) u ofrecer funcionalidad como InsertIfNotExists – saret

Cuestiones relacionadas