2009-07-27 17 views
60

Tengo una variable que estoy utilizando para representar el estado. Se puede leer y escribir desde múltiples hilos.Enclavado y volátil

Estoy usando Interlocked.Exchange y Interlocked.CompareExchange para cambiarlo. Sin embargo, lo estoy leyendo de múltiples hilos.

Sé que volatile se puede utilizar para asegurarse 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 en volátil, genera una advertencia sobre el uso de volátiles y pasa usando ref a los métodos de enclavamiento.

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 la palabra 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.

Se han realizado declaraciones en Internet que no requieren volatilidad si está utilizando los métodos Interbloqueados para todos sus accesos. 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 de lectura segura y escribir de mi variable sin usar el bloqueo?

+2

Buena pregunta en realidad. El uso de un bloqueo regular implica un * punto de ejecución crítico * y garantiza que su valor estará actualizado para todos los hilos. Sin embargo, Interlocked.Exchange no se implementa con 'lock' y no puedo encontrar ninguna referencia que haga tales garantías. – Thorarin

Respuesta

30

Puede ignorar con seguridad esa advertencia cuando esté usando las funciones Interlocked.Xxx (consulte this question), ya que siempre realizan operaciones volátiles. Entonces una variable volatile está perfectamente bien para el estado compartido. Si desea deshacerse de la advertencia a toda costa, realmente puede hacer una lectura entrelazada con Interlocked.CompareExchange (ref counter, 0, 0).

Editar: En realidad, es necesario volatile en su variable de estado solamente si se va a escribir en él directamente (es decir, no utilizando Interlocked.Xxx). As jerryjvl mentioned, las lecturas de una variable actualizada con una operación entrelazada (o volátil) usarán el valor más reciente.

+0

Donde debería reemplazar 0 con un valor que mi variable nunca será? – trampster

+3

Uf, si no fuera así, Interlocked sería bastante inútil. Me asusté allí por un minuto :) – Thorarin

+0

@Daniel: no, la constante no importa, porque 'CompareExchange' reemplazará a' 0' con '0' si' counter' es '0' - es decir, no-op. –

31

En realidad, no se supone que las operaciones entrelazadas y los 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.

El exceso de simplificación y paráfrasis:
volatile indica que cada operación de lectura tiene que volver a leer de la memoria porque puede haber otros hilos actualización de 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, porque hace que la memoria caché se vacíe para que la actualización sea visible para todos los demás procesadores ... esto tiene el beneficio de que usted pone la sobrecarga 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.

+0

OK, entonces si solo estoy usando Interlocked para escribir, entonces las lecturas normales siempre estarán actualizadas. – trampster

+0

Generalmente eso debería hacer el trabajo, sí ... es por eso que (aparte de por mucho tiempo) no hay operaciones de enclavamiento solo para valores de lectura. – jerryjvl

+2

No hay nada intrínsecamente incorrecto al usar volátiles y enclavados entre sí. La razón por la que recibes una advertencia es que "volátil" es que "volátil" no es parte del sistema de tipo, y el destinatario que recibe la referencia no sabrá que la variable referenciada necesita acceso volátil. –