for - multithreading c# book
Generadores de barrera de memoria (3)
Aquí está mi opinión sobre el tema e intentar proporcionar una lista casi completa en una respuesta. Si encuentro otros, editaré mi respuesta de vez en cuando.
Mecanismos generalmente acordados para causar barreras implícitas:
- Todos los métodos de clase
Monitor
, incluido ellock
palabra clave C # - Todos los métodos de clase entrelazados.
- Todos los métodos de clase
Volatile
(.NET 4.5+). - La
SpinLock
métodos deSpinLock
incluyenEnter
yExit
. -
Thread.Join
-
Thread.VolatileRead
yThread.VolatileWrite
-
Thread.MemoryBarrier
- La palabra clave
volatile
. - Cualquier cosa que inicie un hilo o haga que un delegado se ejecute en otro hilo, incluyendo
QueueUserWorkItem
,Task.Factory.StartNew
,Thread.Start
, el compilador proporcionó los métodos deBeginInvoke
, etc. - Usando un mecanismo de señalización como
ManualResetEvent
,AutoResetEvent
,CountdownEvent
,Semaphore
,Barrier
, etc. - Uso de operaciones de cálculo de referencias como
Control.Invoke
,Dispatcher.Invoke
,SynchronizationContext.Post
, etc.
Mecanismos que se especulan (pero no se sabe con certeza) que causan barreras implícitas:
-
Thread.Sleep
(propuesto por mí mismo y posiblemente por otros debido a que el código que presenta un problema de barrera de memoria se puede solucionar con este método) -
Thread.Yield
-
Thread.SpinWait
-
Lazy<T>
según elLazyThreadSafetyMode
especificado
Otras menciones notables:
- Agregue y elimine de forma predeterminada controladores para eventos en C #, ya que usan
lock
oInterlocked.CompareExchange
. - Las tiendas x86 tienen semántica de vallas de liberación
- La implementación de Microsoft de la CLI tiene una semántica de vallas de liberación en las escrituras a pesar del hecho de que la especificación ECMA no lo exige.
-
MarshalByRefObject
parece suprimir ciertas optimizaciones en subclases que pueden hacer que parezca como si estuviera presente una barrera de memoria implícita. Gracias a Hans Passant por descubrir esto y llamar mi atención. 1
1 Esto explica por qué BackgroundWorker
funciona correctamente sin tener volatile
en el campo subyacente para la propiedad CancellationPending
.
Al leer el tutorial de enhebrado de Joseph Albahari , se menciona a los siguientes como generadores de barreras de memoria:
- Declaración de
lock
C # (Monitor.Enter
/Monitor.Exit
) - Todos los métodos en la clase
Interlocked
- Devoluciones de llamada asincrónicas que utilizan el grupo de subprocesos: estos incluyen delegados asincrónicos, devoluciones de llamada de APM y continuaciones de tareas
- Configuración y espera en una construcción de señalización
- Todo lo que dependa de la señalización, como iniciar o esperar en una tarea
Además, Hans Passant y Brian Gideon agregaron lo siguiente (asumiendo que ninguno de los que ya encaja en una de las categorías anteriores):
- Comenzar o despertar un hilo
- Cambio de contexto
-
Thread.Sleep()
Me preguntaba si esta lista estaba completa (si una lista completa podría hacerse prácticamente)
EDITAR adiciones sugeridas:
- Volátil (la lectura implica una valla de adquisición, la escritura implica una valla de liberación)
La palabra clave volatile
actúa como una barrera de memoria. Ver http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx
Me parece recordar que las implementaciones de los métodos Thread.VolatileRead y Thread.VolatileWrite en realidad causan vallas completas, no medias vallas.
Esto es profundamente desafortunado, ya que las personas podrían haber llegado a confiar en este comportamiento sin saberlo; Es posible que hayan escrito un programa que requiera una valla completa, crean que necesitan una valla y creen que están recibiendo una media valla, y se encontrarán con una desagradable sorpresa si una implementación de estos métodos alguna vez proporciona una valla media.
Evitaría estos métodos. Por supuesto, evitaría todo lo relacionado con el código de bloqueo bajo, no siendo lo suficientemente inteligente como para escribirlo correctamente en cualquier cosa que no sean los casos más triviales.