la asignación de referencia es atómica así que ¿por qué se necesita el Interlocking.Exchange (ref Object, Object)?

En mi servicio web multithreaded asmx, tenía un campo de clase _allData de mi tipo, SystemData, que consta de pocas List y Dictionary marcadas como volatile . Los datos del sistema ( _allData ) se actualizan de vez en cuando y lo hago creando otro objeto llamado newData y llenando sus estructuras de datos con nuevos datos. Cuando termina, solo asigno

 private static volatile SystemData _allData public static bool LoadAllSystemData() { SystemData newData = new SystemData(); /* fill newData with up-to-date data*/ ... _allData = newData. } 

Esto debería funcionar ya que la asignación es atómica y los hilos que tienen la referencia a los datos antiguos continúan usándola y el rest tiene los datos del nuevo sistema justo después de la asignación. Sin embargo, mi colega dijo que en lugar de usar palabras clave volatile y asignación simple debería usar InterLocked.Exchange porque dijo que en algunas plataformas no se garantiza que la asignación de referencia sea atómica. Además: cuando declaro the _allData campo the _allData como volatile

 Interlocked.Exchange(ref _allData, newData); 

produce una advertencia “una referencia a un campo volátil no se tratará como volátil” ¿Qué debería pensar al respecto?

Hay numerosas preguntas aquí. Considerándolos uno a la vez:

la asignación de referencia es atómica así que ¿por qué se necesita el Interlocking.Exchange (ref Object, Object)?

La asignación de referencia es atómica. Interlocked.Exchange no hace solo asignación de referencia. Hace una lectura del valor actual de una variable, esconde el valor anterior y asigna el nuevo valor a la variable, todo como una operación atómica.

mi colega dijo que en algunas plataformas no está garantizado que la asignación de referencia sea atómica. ¿Mi colega estaba en lo correcto?

No. La asignación de referencia está garantizada para ser atómica en todas las plataformas .NET.

Mi colega está razonando desde premisas falsas. ¿Eso significa que sus conclusiones son incorrectas?

No necesariamente. Su colega podría estar brindándole buenos consejos por malas razones. Tal vez haya alguna otra razón por la que debería estar utilizando Interlocked.Exchange. La progtwigción sin lockings es increíblemente difícil y en el momento en que te desvíes de las prácticas bien establecidas expuestas por expertos en el campo, estás perdido en las malas hierbas y arriesgando el peor tipo de condiciones de carrera. No soy un experto en este campo ni un experto en su código, por lo que no puedo emitir un juicio en un sentido u otro.

produce una advertencia “una referencia a un campo volátil no se tratará como volátil” ¿Qué debería pensar al respecto?

Debes entender por qué esto es un problema en general. Eso conducirá a una comprensión de por qué la advertencia no es importante en este caso particular.

La razón por la que el comstackdor da esta advertencia es porque marcar un campo como volátil significa que “este campo se actualizará en varios subprocesos: no genere ningún código que almacene en caché los valores de este campo, y asegúrese de que cualquier lectura o escritura de este campo no se “mueve hacia adelante y hacia atrás en el tiempo” a través de incoherencias de la memoria caché del procesador “.

(Supongo que ya comprende todo eso. Si no tiene una comprensión detallada del significado de volátiles y cómo afecta a la semántica de la memoria caché del procesador, entonces no comprende cómo funciona y no debería usar progtwigs volátiles. es muy difícil hacerlo bien, asegúrese de que su progtwig sea correcto porque usted entiende cómo funciona, no por accidente).

Ahora suponga que crea una variable que es un alias de un campo volátil pasando una referencia a ese campo. ¡Dentro del método llamado, el comstackdor no tiene ninguna razón para saber que la referencia necesita tener semántica volátil! El comstackdor generará código alegremente para el método que no implementa las reglas para los campos volátiles, pero la variable es un campo volátil. Eso puede arruinar completamente tu lógica sin locking; la suposición es siempre que se accede siempre a un campo volátil con semántica volátil. No tiene sentido tratarlo como volátil a veces y no en otras ocasiones; siempre debe ser consistente, de lo contrario no puede garantizar la coherencia en otros accesos.

Por lo tanto, el comstackdor advierte cuando haces esto, ya que es probable que arruine por completo tu lógica cuidadosamente desarrollada.

Por supuesto, Interlocked.Exchange está escrito para esperar un campo volátil y hacer lo correcto. La advertencia es, por lo tanto, engañosa. Lamento mucho esto; lo que deberíamos haber hecho es implementar algún mecanismo mediante el cual un autor de un método como Interlocked.Exchange podría poner un atributo en el método que diga “este método que toma una referencia semántica volátil sobre la variable, así que suprima la advertencia”. Quizás en una versión futura del comstackdor lo haremos.

O su colega está equivocada, o él sabe algo que la especificación del lenguaje C # no.

5.5 Atomicidad de las referencias variables :

“Las lecturas y escrituras de los siguientes tipos de datos son atómicos: bool, char, byte, sbyte, corto, ushort, uint, int, float y tipos de referencia”.

Por lo tanto, puede escribir en la referencia volátil sin riesgo de obtener un valor dañado.

Por supuesto, debe tener cuidado con la forma de decidir qué hilo debe recuperar los nuevos datos, para minimizar el riesgo de que más de un hilo a la vez lo haga.

Interbloqueado. Intercambio

Establece una variable del tipo especificado T en un valor especificado y devuelve el valor original, como una operación atómica.

Cambia y devuelve el valor original, es inútil porque solo quieres cambiarlo y, como dijo Guffa, ya es atómico.

A menos que un generador de perfiles haya demostrado que es un cuello de botella en su aplicación, debe considerar el uso de lockings, es más fácil de entender y probar que su código es correcto.

Iterlocked.Exchange() no es solo atómico, sino que también se encarga de la visibilidad de la memoria:

Las siguientes funciones de sincronización utilizan las barreras apropiadas para garantizar el orden de la memoria:

Funciones que entran o salen de secciones críticas

Funciones que señalan objetos de sincronización

Funciones de espera

Funciones enclavadas

Sincronización y problemas de multiprocesador

Esto significa que, además de la atomicidad, asegura que:

  • Para el hilo que lo llama:
    • No se realiza ningún reordenamiento de las instrucciones (por el comstackdor, el tiempo de ejecución o el hardware).
  • Para todos los hilos:
    • No hay lecturas en memoria que ocurran antes de que esta instrucción vea el cambio realizado en esta instrucción.
    • Todas las lecturas posteriores a esta instrucción verán el cambio realizado por esta instrucción.
    • Todas las escrituras en la memoria después de esta instrucción sucederán después de que este cambio de instrucción haya llegado a la memoria principal (mediante el lavado de esta instrucción, cambie a la memoria principal cuando haya terminado y no permita que el hardware descargue su propio tiempo).
    Intereting Posts