c# - net - Enclavado y volátil
mono sdk 5.12 0 linux (2)
No se supone que las operaciones entrelazadas y volátiles se usen al mismo tiempo. La razón por la que recibe una advertencia es porque (¿casi?) Siempre indica que ha entendido mal lo que está haciendo.
Sobre simplificando y parafraseando:
volatile
indica que cada operación de lectura necesita volver a leerse de la memoria porque puede haber otros subprocesos actualizando la variable. Cuando se aplica a un campo que puede leerse / escribirse atómicamente por la arquitectura en la que se está ejecutando, esto debería ser todo lo que necesita hacer a menos que esté utilizando long / ulong, la mayoría de los otros tipos pueden leerse o escribirse atómicamente.
Cuando un campo no está marcado como volátil, puede usar operaciones Interlocked
para hacer una garantía similar, ya que hace que se vacíe la memoria caché para que la actualización sea visible para todos los demás procesadores ... esto tiene el beneficio de que pone los gastos generales en la actualización en lugar de la lectura.
Cuál de estos dos enfoques rinde mejor depende de qué está haciendo exactamente. Y esta explicación es una simplificación excesiva. Pero debe quedar claro a partir de esto que hacer ambas cosas al mismo tiempo no tiene sentido.
Tengo una variable que estoy usando para representar el estado. Se puede leer y escribir desde múltiples hilos.
Estoy usando Interlocked.Exchange
y Interlocked.CompareExchange
para cambiarlo. Sin embargo, lo estoy leyendo de múltiples hilos.
Sé que se puede usar volatile
para asegurarme de que la variable no se almacena en la memoria caché localmente, sino que siempre se lee directamente desde la memoria.
Sin embargo, si configuro la variable como volátil, genera una advertencia sobre el uso de volátiles y el paso usando ref para los métodos enclavados.
Quiero asegurarme de que cada hilo esté leyendo el valor más reciente de la variable y no una versión en caché, pero no puedo usar el elemento volátil.
Hay un Interlocked.Read
pero es para tipos de 64 bits y no está disponible en el marco compacto. La documentación para él dice que no es necesario para tipos de 32 bits, ya que se realizan en una sola operación.
Hay declaraciones hechas en Internet que indican que no necesita volátiles si usa los métodos Interbloqueados para todo su acceso. Sin embargo, no puede leer una variable de 32 bits con los métodos de enclavamiento, por lo que no hay forma de que pueda usar métodos enclavados para todo su acceso.
¿Hay alguna manera de lograr el hilo seguro de lectura y escritura de mi variable sin usar el bloqueo?
Puede ignorar esa advertencia de forma segura cuando usa funciones Interlocked.Xxx
(consulte esta pregunta ), ya que siempre realizan operaciones volátiles. Entonces, una variable volatile
está perfectamente bien para el estado compartido. Si quiere deshacerse de la advertencia a toda costa, puede hacer una lectura entrelazada con Interlocked.CompareExchange (ref counter, 0, 0)
.
Editar: en realidad, necesita volatile
en su variable de estado solo si va a escribir directamente (es decir, sin utilizar Interlocked.Xxx
). Como mencionó jerryjvl , las lecturas de una variable actualizada con una operación entrelazada (o volátil) usarán el valor más reciente.