¿Las matrices C # son seguras?

En particular

  1. Crea una función para tomar una matriz y un índice como parámetros.
  2. Crea una matriz de elementos.
  3. Crear un bucle de conteo
  4. Dentro del ciclo de un nuevo hilo asigne una nueva instancia del objeto a la matriz usando el indexador pasado.

Sé cómo administrar los hilos, etc. Me interesa saber si esta es la forma segura de hacer algo.

class Program { // bogus object class SomeObject { private int value1; private int value2; public SomeObject(int value1, int value2) { this.value1 = value1; this.value2 = value2; } } static void Main(string[] args) { var s = new SomeObject[10]; var threads = Environment.ProcessorCount - 1; var stp = new SmartThreadPool(1000, threads, threads); for (var i = 0; i < 10; i++) { stp.QueueWorkItem(CreateElement, s, i); } } static void CreateElement(SomeObject[] s, int index) { s[index] = new SomeObject(index, 2); } } 

Creo que si cada hilo solo funciona en una parte separada de la matriz, todo estará bien. Si va a compartir datos (es decir, lo comunicará entre hilos), necesitará algún tipo de barrera de memoria para evitar problemas con el modelo de memoria.

Creo que si generas un montón de hilos, cada uno de los cuales llena su propia sección de la matriz, entonces espera a que todos esos hilos terminen de usar Thread.Join , eso hará lo suficiente en términos de barreras para que estés a salvo. . No tengo ninguna documentación de respaldo para eso en este momento, fíjate …

EDITAR: su código de muestra es seguro. En ningún momento hay dos hilos que acceden al mismo elemento, es como si cada uno tuviera variables separadas. Sin embargo, eso no tiende a ser útil por sí mismo. En algún momento, normalmente los hilos querrán compartir el estado: un hilo querrá leer lo que otro ha escrito. De lo contrario, no tiene sentido que escriban en una matriz compartida en lugar de en sus propias variables privadas. Ese es el punto en el que debe tener cuidado: la coordinación entre hilos.

La documentación de MSDN en Arrays dice:

Los miembros públicos estáticos (Shared en Visual Basic) de este tipo son seguros para subprocesos. No se garantiza que ningún miembro de instancia sea seguro para subprocesos.

Esta implementación no proporciona un contenedor sincronizado (thread safe) para una matriz; sin embargo, las clases .NET Framework basadas en Array proporcionan su propia versión sincronizada de la colección utilizando la propiedad SyncRoot.

Enumerar a través de una colección no es intrínsecamente un procedimiento seguro para subprocesos. Incluso cuando una colección está sincronizada, otros subprocesos aún pueden modificar la colección, lo que hace que el enumerador genere una excepción. Para garantizar la seguridad del subproceso durante la enumeración, puede bloquear la recostackción durante toda la enumeración o atrapar las excepciones resultantes de los cambios realizados por otros subprocesos.

Entonces no, no están seguros para subprocesos.

En general, cuando se dice que una colección es ‘no insegura’ eso significa que los accesos simultáneos pueden fallar internamente (por ejemplo, no es seguro leer el primer elemento de la Lista mientras que otro subproceso agrega un elemento al final de la lista: la Lista podría cambiar el tamaño de la matriz subyacente y el acceso de lectura podría ir a la nueva matriz antes de que los datos se copiaran en ella).

Dichos errores son imposibles con las matrices porque las matrices son de tamaño fijo y no tienen tales ‘cambios de estructura’. Una matriz con tres elementos no es más o menos segura para subprocesos que tres variables.

La especificación C # no dice nada sobre esto; pero está claro si conoce IL y lee la especificación CLI: puede obtener una referencia administrada (como las utilizadas para los parámetros “ref” de C #) a un elemento dentro de una matriz y luego realizar cargas normales y volátiles y almacenar en ella. La especificación CLI describe las garantías de seguridad de subprocesos para tales cargas y almacenes (p. Ej., Atomicidad para elementos < = 32 bit)

Entonces, si estoy entendiendo correctamente su pregunta, ¿desea llenar una matriz utilizando diferentes hilos, pero asignará a cada elemento de la matriz una sola vez? Si es así, es perfectamente seguro para subprocesos.

El ejemplo que proporciona es muy similar a la forma en que funcionan las extensiones paralelas propias de Microsoft para C # 4.0.

Esto para bucle:

 for (int i = 0; i < 100; i++) { a[i] = a[i]*a[i]; } 

se convierte

 Parallel.For(0, 100, delegate(int i) { a[i] = a[i]*a[i]; }); 

Entonces, sí, tu ejemplo debería estar bien. Aquí hay una publicación de blog más antigua sobre el nuevo soporte paralelo en C #.