2009-09-22 11 views
42

En particular¿Las matrices C# son seguras?

  1. crear una función para tomar una matriz y un índice como parámetros.
  2. Crea una matriz de elementos n.
  3. Crear un ciclo n count.
  4. Dentro del bucle en un nuevo hilo de asignar una nueva instancia del objeto a la matriz mediante el indizador se ha pasado.

Sé cómo manejar los hilos etc. Estoy interesado en saber si este es el hilo 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); 
    } 
} 
+20

Esto no es para nada el objetivo de la pregunta, pero desaconsejaría usar 'Environment.ProcessorCount - 1' - esas personas de un solo núcleo estarían descontentas si no ... –

+6

Hay personas con procesadores de núcleo? – Gary

+4

@Gary hay máquinas virtuales con "un" procesador;) – IamIC

Respuesta

39

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

I creo que si generar un haz de hilos, cada uno de los cuales puebla su propia sección de la matriz, y luego esperar a que todos esos hilos para terminar usando Thread.Join, que eso hacer lo suficiente en términos de barreras para tu para estar seguro. No tengo ninguna documentación de respaldo para eso en este momento, fíjate ...

EDITAR: El 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. Eso es punto en el que debe tener cuidado: la coordinación entre los hilos.

+3

Los elementos de matriz siguen las mismas reglas que las variables regulares, en ese intercambio una referencia será atómica pero en general no se reemplazará una estructura. Sin embargo, esto no tiene en cuenta la necesidad de una barrera de memoria para hacer los accesos volátiles. Como dijiste, si es seguro va a depender precisamente de lo que está haciendo el codificador. –

+0

@Steven: Sí, eso fue sobre mi comprensión :) –

+2

@Steven "si es seguro va a depender precisamente de lo que está haciendo el codificador". - ¿No es lo mismo que decir "No, no es seguro"? ? – Rik

24

MSDN documentation on Arrays dice:

estáticos públicos (Shared en Visual Basic) miembros de este tipo son seguros para subprocesos. Cualquier miembro de instancia no es garantizado para ser seguro para subprocesos.

Esta implementación no proporciona una envoltura sincronizada (hilo seguro) para una matriz; sin embargo, las clases de .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 es intrínsecamente no es un procedimiento seguro hilo. Incluso cuando una colección está sincronizada , otros hilos pueden todavía modificar la colección, lo que hace que el enumerador arroje una excepción. Para garantizar la seguridad de subprocesos durante la enumeración , puede bloquear la colección durante toda la enumeración o detectar las excepciones resultantes de los cambios realizados por otros subprocesos .

Así que no, no son seguros para subprocesos.

+13

Esto no responde mi pregunta. No estoy haciendo ninguna enumeración, ¿cómo puede este tipo obtener 13 votos? – Gary

+4

Un voto significa que la respuesta es útil. Su marca de verificación indica que una respuesta resuelve su problema. Dada esta información, si estuviera desarrollando una clase susceptible de ser modificada con Arrays, creo que lo primero que haría sería activar Reflector, abrir una de las clases Framework que usa Array en un contexto seguro para subprocesos y ver qué están haciendo. con SyncRoot. –

+6

Esta respuesta es realmente inútil, ya que la cita de MSDN es bastante engañosa * y * no al grano. Los accesos de matriz a los tipos de referencia son atómicos; incluso la enumeración sobre tal matriz (aunque probablemente no sea prudente) es en ese grado segura para hilos. –

11

En general, cuando se dice que una colección de ser 'no-hilo' que significa que los accesos concurrentes podrían fallar internamente (por ejemplo, que no es seguro para leer el primer elemento de la lista < T>, mientras que otro hilo añade un elemento al final de la lista: la lista < T> podría cambiar el tamaño de la matriz subyacente y el acceso de lectura podría ir a la nueva matriz antes de copiar los datos en ella).

Tales errores son imposibles en 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 al respecto; 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 de CLI describe las garantías de seguridad de subprocesos para tales cargas y tiendas (p. Ej., Atomicidad para los elementos < = 32 bit)

Así que si estoy entendiendo correctamente su pregunta, desea llenar una matriz utilizando diferentes subprocesos, pero asignar a cada elemento de la matriz solo una vez? Si es así, es perfectamente seguro para subprocesos.

4

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

Este bucle for:

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

convierte

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

Así que, sí, su ejemplo debería estar bien. Aquí hay un blog post más antiguo sobre el nuevo soporte paralelo en C#.

Cuestiones relacionadas