subprocesos procesadores calcular calculando c# .net multithreading

c# - procesadores - garantiza que el valor actualizado de la variable siempre esté visible para varios subprocesos en un sistema multiprocesador



calculando 4 procesadores excel 2016 (8)

A partir de esto puedo entender que desea poder leer el último valor que se escribió en un campo. Vamos a hacer una analogía con el problema de la concurrencia de SQL de los datos. Si desea poder leer el último valor de un campo, debe realizar instrucciones atómicas. Si alguien está escribiendo un campo, todos los hilos deben estar bloqueados para leer hasta que ese hilo termine la transacción de escritura. Después de eso, cada lectura en ese hilo estará segura. El problema no es con la lectura como con la escritura. Un bloqueo en ese campo siempre que su escritura sea suficiente si me preguntas ...

Estoy usando tal configuración:

  • .NET framework 4.5
  • Windows Server 2008 R2
  • HP DL360p Gen8 (2 * Xeon E5-2640, x64)

Tengo tal campo en algún lugar de mi programa:

protected int HedgeVolume;

Accedo a este campo desde varios hilos. Supongo que, como tengo un sistema multiprocesador, es posible que estos subprocesos se ejecuten en diferentes procesadores.

¿Qué debo hacer para garantizar que cada vez que use este campo el valor más reciente sea "leído"? ¿Y para asegurarme de que cuando "escribo" el valor esté disponible para todos los demás subprocesos inmediatamente?

¿Qué tengo que hacer?

  • acaba de salir del campo como es.
  • declararlo volatile
  • Usa la clase de Interlocked para acceder al campo.
  • use .NET 4.5 Volatile.Read , Volatile.Write métodos para acceder al campo
  • usar lock

Solo necesito la forma más sencilla de hacer que mi programa funcione en esta configuración . No necesito que mi programa funcione en otras computadoras, servidores o sistemas operativos. También quiero una latencia mínima, así que busco la solución más rápida que siempre funcione en esta configuración estándar (multiprocesador Intel x64, .net 4.5).


A su pregunta le falta un elemento clave ... ¿Qué tan importante es la integridad de los datos en ese campo?

volatile le proporciona rendimiento, pero si un hilo está actualmente escribiendo cambios en el campo, no obtendrá esos datos hasta que esté listo, por lo que podría acceder a información desactualizada y, posiblemente, sobrescribir cambios que otro hilo está haciendo actualmente. Si los datos son confidenciales, podría obtener errores que serían muy difíciles de rastrear. Sin embargo, si está realizando una actualización muy rápida, sobrescriba el valor sin leerlo y no le importa que de vez en cuando obtenga datos obsoletos (unos pocos ms), hágalo.

lock garantía de que solo un hilo puede acceder al campo a la vez. Puede ponerlo solo en los métodos que escriben el campo y dejar el método de lectura solo. El lado negativo es que es lento y puede bloquear un hilo mientras otro está realizando su tarea. Sin embargo, está seguro de que sus datos permanecen válidos.

Interlock existe para protegerse del cambio de contexto del planificador. ¿Mi opinión? No lo use a menos que sepa exactamente por qué lo usaría y exactamente cómo usarlo. Da opciones, pero con grandes opciones viene gran problemática. Evita un cambio de contexto mientras se actualiza una variable. Puede que no haga lo que usted cree que hace y no evitará que los hilos paralelos realicen sus tareas simultáneamente.


Cuando empiece a diseñar un programa concurrente, debe considerar estas opciones en orden de preferencia:

1) Aislamiento: cada hilo tiene sus propios datos privados.
2) Inmutabilidad: los hilos pueden ver el estado compartido, pero nunca cambia
3) Estado compartido mutable: proteja todos los accesos al estado compartido con bloqueos

Si llega a (3), ¿qué tan rápido realmente necesita que sea esto?

La adquisición de un bloqueo sin oposición toma del orden de 10 ns (10 -8 segundos): es lo suficientemente rápido para la mayoría de las aplicaciones y es la forma más sencilla de garantizar la corrección.

El uso de cualquiera de las otras opciones que mencionas te lleva al ámbito de la programación de bloqueo bajo, que es increíblemente difícil de corregir.

Si desea aprender a escribir software concurrente, debe leer estos:

Introducción: el libro electrónico gratuito de Joe Albahari : tomará aproximadamente un día leerlo

Biblia: "Programación concurrente en Windows" de Joe Duffy : tomará aproximadamente un mes leer


Depende de lo que HAGAS. Solo para lectura, lo más volátil es más fácil, entrelazado permite un poco más de control. El bloqueo no es necesario ya que es más complejo que el problema que describe. No estoy seguro acerca de Volatile.Read/Write, nunca los usé.


Desea utilizar Volatile.Read() .

Como está ejecutando en x86, todas las escrituras en C # son el equivalente de Volatile.Write() , solo necesita usar esto para Itanium.

Volatile.Read() se asegurará de que obtengas la última copia, independientemente del hilo que la escribió por última vez.

Hay una escritura fantástica aquí, Explicación del modelo de memoria C #

Resumen del mismo incluye,

En algunos procesadores, el compilador no solo debe evitar ciertas optimizaciones en las lecturas y escrituras volátiles, sino que también tiene que usar instrucciones especiales. En una máquina multi-core, diferentes núcleos tienen diferentes cachés. Es posible que los procesadores no se molesten en mantener esos cachés coherentes de forma predeterminada, y se pueden necesitar instrucciones especiales para vaciar y actualizar los cachés.

Esperemos que eso sea obvio, aparte de la necesidad de volatile para evitar que el compilador lo optimice, también está el procesador.

Sin embargo, en C # todas las escrituras son volátiles (a diferencia de, por ejemplo, en Java), independientemente de si escribe en un campo volátil o no volátil. Por lo tanto, la situación anterior en realidad nunca sucede en C #. Una escritura volátil actualiza el caché del hilo, y luego vacía todo el caché a la memoria principal.

No necesita Volatile.Write() . Más fuente autoritativa aquí, Joe Duffy CLR Memory Model . Sin embargo, es posible que lo necesite para detener el compilador que lo reordena.

Dado que todas las escrituras en C # son volátiles, puede pensar que todas las escrituras van directamente a la memoria principal. Una lectura regular, no volátil, puede leer el valor de la caché del hilo, en lugar de hacerlo desde la página principal.

Necesitas Volatile.Read()


Primero eche un vistazo aquí: Volatile vs. Interlocked vs. lock

El modificador volátil shurely es una buena opción para una CPU de varios núcleos.

¿Pero es esto suficiente? Depende de cómo calcule el nuevo valor de HedgeVolume!

  • Si su nuevo HedgeVolume no depende del HedgeVolume actual, habrá terminado con volatile.

  • Pero si HedgeVolume [x] = f (HedgeVolume [x-1]) necesita un poco de sincronización de hilos para garantizar que HedgeVolume no cambie mientras calcula y asigna el nuevo valor. Tanto el bloqueo como los szenarios entrelazados serían adecuados en este caso.


Tuve una pregunta similar y encontré este artículo extremadamente útil. Es una lectura muy larga, ¡pero aprendí MUCHO!


volatile - malo, hay algunos problemas (ver el blog de Joe Duffy)

Si todo lo que hace es leer el valor o escribir un valor incondicionalmente, use Volatile.Read y Volatile.Write

Si necesita leer y posteriormente escribir un valor actualizado, use la sintaxis de lock . Sin embargo, puede lograr el mismo efecto sin bloqueo utilizando la funcionalidad de clases CompareExchange , pero esto es más complejo (involucra a CompareExchange s para asegurarse de que está actualizando el valor de lectura, es decir, no se ha modificado desde la operación de lectura + lógica para reintentar si el valor era modificado desde la lectura).