2010-10-28 8 views
15

¿Puedo, sin bloqueo, llamar de manera segura a List.AddRange (r) desde varios subprocesos? Si no, ¿con qué tipo de problema me encontraría?¿Es seguro el subproceso de la lista <T> .AddRange()?

+1

btw - re '¿qué tipo de problema?' - es probable que obtenga una Excepción, en algún momento al azar cuando varios hilos entran en conflicto –

Respuesta

17

No, its documentation no dice que es seguro para subprocesos, por lo tanto, no lo es.

Público estático (compartido en Visual Basic) miembros de este tipo son seguros para subprocesos. Cualquier miembro de instancia no es garantizado para ser seguro para subprocesos.

En cuanto a lo que puede salir mal, piensa en lo AddRange (newitems) hace:

  • Comprobar si hay suficiente espacio en la matriz interna
  • Si no es así:
    • Asignar una nueva matriz
    • Copie los elementos actuales a la nueva matriz
    • Establezca un campo para apuntar al nuevo arr ay
  • Copiar los newitems al local correcta en la matriz interna
  • actualización de la “cuenta” de campo (esto se utiliza para controlar donde se inserta el siguiente punto)

Ahora piensa en lo que se sucede si lo anterior está mezclado con otra llamada a AddRange() o incluso solo una llamada para leer un elemento.

1

No, no es seguro para subprocesos.

El hilo A podría llamar a AddRange en su lista. Podría iterar parcialmente sobre la colección y cambiar los hilos.

El hilo B podría llamar Agregar/Quitar, etc. antes de que el hilo A haya finalizado.

6

No, no es así, pero me gustaría agregar que es más eficiente hacer un myList.AddRange(...); dentro de un bloqueo que haciendo varios lock (syncLock) { myList.Add(...) };.

¿Con qué tipo de problema se encontraría? Cuando un hilo está agregando un elemento mientras que otro está enumerando la lista, List<T> arrojará una cierta excepción porque hace algunas versiones internas, ya que quiere evitar que nosotros, los desarrolladores pobres, peguemos con desagradables efectos secundarios.

También el List<T> mantiene internamente una matriz en la que almacena sus elementos. Tal vez establecer un elemento en una matriz sea bastante atómico, pero cada vez que se alcance la capacidad de esta matriz, se creará una nueva y los elementos se copiarán de la anterior. Entonces, cuando un hilo desea agregar algo mientras se realiza esa copia, puede imaginarse que las cosas se desincronizarán.

+0

Excelente respuesta, gracias. =) –

3

Hasta .NET Framework 4.0, ninguna colección .NET es segura para subprocesos. A continuación, se le pedirá que lo bloquee antes de acceder a él en su código Collections and Synchronization (Thread Safety).

Por otro lado, .NET Framework 4.0 introduce el nuevo espacio de nombre System.Collections.Concurrent que incluye Thread-Safe Collections de grano fino.

Finalmente, si puede usar .NET Framework 4.0, le recomiendo que lo haga para lo que necesita; de lo contrario, asegúrese de bloquear la colección cada vez que quiera modificarla o acceder a ella.

Además, una colección estática debe ser segura para subprocesos, pero tenga cuidado, ya que no se garantiza que los miembros sean.

editar # 1

Después de comprobaciones adicionales debido al comentario de Steve Townsend, admito que hay tres colecciones compatibles con el proceso dentro del marco .NET partir de la versión 3.0:

  1. SynchronizedCollection Generic Class;
  2. SynchronizedKeyedCollection Generic Class;
  3. SynchronizedReadOnlyCollection Generic Class.

Disculpe, acabo de aprender su extenuación yo mismo. =)

+0

no es cierto, hay algunos en 'System.Collections.Generic' que funcionan aquí y son anteriores a 4.0 –

+0

@Steve Townsend: Después de la verificación, tienes razón, estoy equivocado. Además, la colección genérica 'IList ' no lo es, aunque no había considerado esto 'SynchronizedCollection ', ya que no sabía nada al respecto. = P ¡Gracias por informarme! –

+1

No hay problema. Te debo un +1 por mencionar las 4.0 colecciones. –

3

Dependiendo de su uso, SynchronizedCollection podría funcionar.

No tendría un solo disparo AddRange sin embargo. Si solo está utilizando esto para inicializar la colección, puede hacerlo ya que hay una sobrecarga de constructor IEnumerable.

+1

+1 ¡Acabo de aprender algo nuevo hoy! ¡Gracias! =) –

+0

Gracias por su voto positivo. Me gustaría hacerle saber que he editado mi respuesta para reflejar esta nueva información que me brindó (a todos nosotros). –

Cuestiones relacionadas