stringtranslate.com

volátil (programación informática)

En programación de computadoras , volátil significa que un valor es propenso a cambiar con el tiempo, fuera del control de algún código. La volatilidad tiene implicaciones dentro de las convenciones de llamada de funciones y también afecta la forma en que se almacenan, acceden y almacenan en caché las variables.

En los lenguajes de programación C , C++ , C# y Java , la palabra clave volátil indica que un valor puede cambiar entre diferentes accesos, incluso si no parece estar modificado. Esta palabra clave evita que un compilador de optimización optimice lecturas o escrituras posteriores y, por lo tanto, reutilice incorrectamente un valor obsoleto u omita escrituras. Los valores volátiles surgen principalmente en el acceso al hardware ( E/S asignadas en memoria ), donde se utiliza la lectura o escritura en la memoria para comunicarse con dispositivos periféricos , y en el subproceso , donde un subproceso diferente puede haber modificado un valor.

A pesar de ser una palabra clave común, el comportamiento de volatiledifiere significativamente entre lenguajes de programación y es fácil de malinterpretar. En C y C++, es un calificador de tipo , como const, y es una propiedad del tipo . Además, en C y C++ no funciona en la mayoría de los escenarios de subprocesamiento y se desaconseja su uso. En Java y C#, es una propiedad de una variable e indica que el objeto al que está vinculada la variable puede mutar y está diseñado específicamente para subprocesos. En el lenguaje de programación D , hay una palabra clave separada sharedpara el uso de subprocesos, pero no volatileexiste ninguna palabra clave.

En C y C++

En C, y en consecuencia en C++, la volatilepalabra clave tenía como objetivo: [1]

Dado que las variables marcadas como volátiles son propensas a cambiar fuera del flujo de código estándar, el compilador debe realizar cada lectura y escritura en la variable como lo indica el código. Cualquier acceso a variables volátiles no se puede optimizar, por ejemplo mediante el uso de registros para el almacenamiento de valores intermedios.

Si bien está previsto tanto en C como en C++, los estándares de C no expresan que la volatilesemántica se refiere al valor l, no al objeto al que se hace referencia. El respectivo informe de defectos DR 476 (a C11) aún está bajo revisión con C17 . [2]

Las operaciones sobre volatilevariables no son atómicas , ni establecen una relación adecuada de ocurre antes para el subprocesamiento. Esto se especifica en los estándares relevantes (C, C++, POSIX , WIN32), [1] y las variables volátiles no son seguras para subprocesos en la gran mayoría de las implementaciones actuales. Por lo tanto, volatilemuchos grupos de C/C++ desaconsejan el uso de palabras clave como mecanismo de sincronización portátil. [3] [4] [5]

Ejemplo de E/S asignadas en memoria en C

En este ejemplo, el código establece el valor almacenado fooen 0. Luego comienza a sondear ese valor repetidamente hasta que cambia a 255:

estático int foo ;  barra vacía ( vacío ) { foo = 0 ;      mientras ( foo ! = 255 ) ; }    

Un compilador optimizador notará que ningún otro código puede cambiar el valor almacenado en fooy asumirá que permanecerá igual en 0todo momento. Por lo tanto, el compilador reemplazará el cuerpo de la función con un bucle infinito similar a este:

void bar_optimized ( void ) { foo = 0 ;      mientras ( verdadero ) ; }  

Sin embargo, foopuede representar una ubicación que otros elementos del sistema informático pueden cambiar en cualquier momento, como un registro de hardware de un dispositivo conectado a la CPU . El código anterior nunca detectaría tal cambio; sin la volatilepalabra clave, el compilador asume que el programa actual es la única parte del sistema que podría cambiar el valor (que es, con diferencia, la situación más común).

Para evitar que el compilador optimice el código como se indica arriba, volatilese utiliza la palabra clave:

estático volátil int foo ;   barra vacía ( vacío ) { foo = 0 ;       mientras ( foo ! = 255 ) ; }    

Con esta modificación, la condición del bucle no se optimizará y el sistema detectará el cambio cuando ocurra.

Generalmente, hay operaciones de barrera de memoria disponibles en plataformas (que están expuestas en C++ 11) que deben preferirse en lugar de volátiles, ya que permiten que el compilador realice una mejor optimización y, lo que es más importante, garantizan un comportamiento correcto en escenarios de subprocesos múltiples; ni la especificación C (anterior a C11) ni la especificación C++ (anterior a C++11) especifican un modelo de memoria multiproceso, por lo que es posible que volátil no se comporte de manera determinista entre sistemas operativos, compiladores y CPU. [6]

Comparación de optimización en C

Los siguientes programas en C y los extractos en lenguaje ensamblador que los acompañan demuestran cómo la volatilepalabra clave afecta la salida del compilador. El compilador en este caso fue GCC .

Al observar el código ensamblador, es claramente visible que el código generado con volatileobjetos es más detallado, haciéndolo más largo para que volatilese pueda cumplir con la naturaleza de los objetos. La volatilepalabra clave evita que el compilador realice optimización en el código que involucra objetos volátiles, asegurando así que cada asignación y lectura de variable volátil tenga un acceso a memoria correspondiente. Sin la volatilepalabra clave, el compilador sabe que no es necesario volver a leer una variable desde la memoria en cada uso, porque no debería haber ninguna escritura en su ubicación de memoria desde ningún otro subproceso o proceso.

C++11

Según el estándar ISO C++11 , la palabra clave volátil solo debe usarse para acceso al hardware; no lo utilice para la comunicación entre subprocesos. Para la comunicación entre subprocesos, la biblioteca estándar proporciona std::atomic<T>plantillas. [7]

en Java

El lenguaje de programación Java también tiene la volatilepalabra clave, pero se utiliza para un propósito algo diferente. Cuando se aplica a un campo, el calificador de Java volatileproporciona las siguientes garantías:

El uso volatilepuede ser más rápido que un bloqueo , pero no funcionará en algunas situaciones antes de Java 5. [10] La gama de situaciones en las que volátil es efectivo se amplió en Java 5; en particular, el bloqueo de doble verificación ahora funciona correctamente. [11]

Cª#

En C# , volatilegarantiza que el código que accede al campo no esté sujeto a algunas optimizaciones no seguras para subprocesos que puedan realizar el compilador, el CLR o el hardware. Cuando un campo está marcado volatile, se le indica al compilador que genere una "barrera de memoria" o "valla" a su alrededor, lo que evita el reordenamiento de las instrucciones o el almacenamiento en caché vinculados al campo. Al leer un volatilecampo, el compilador genera una valla de adquisición , que evita que otras lecturas y escrituras en el campo se muevan antes de la valla. Al escribir en un volatilecampo, el compilador genera una valla de liberación ; esta barrera evita que otras lecturas y escrituras en el campo se muevan después de la barrera. [12]

Solo se pueden marcar los siguientes tipos volatile: todos los tipos de referencia, Single, Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Chary todos los tipos enumerados con un tipo subyacente de Byte, SByte, Int16, UInt16, Int32o UInt32. [13] (Esto excluye las estructuras de valor , así como los tipos primitivos Double, Int64y UInt64) Decimal.

El uso de la volatilepalabra clave no admite campos que se pasan por referencia o variables locales capturadas ; en estos casos, Thread.VolatileReady Thread.VolatileWritedebe usarse en su lugar. [12]

De hecho, estos métodos deshabilitan algunas optimizaciones que normalmente realiza el compilador de C#, el compilador JIT o la propia CPU. Las garantías proporcionadas por Thread.VolatileReady Thread.VolatileWriteson un superconjunto de las garantías proporcionadas por la volatilepalabra clave: en lugar de generar una "media valla" (es decir, una valla de adquisición sólo evita el reordenamiento de instrucciones y el almacenamiento en caché que le preceden), VolatileReady VolatileWritegenerar una "valla completa" que evitar el reordenamiento de instrucciones y el almacenamiento en caché de ese campo en ambas direcciones. [12] Estos métodos funcionan de la siguiente manera: [14]

Los métodos Thread.VolatileReady Thread.VolatileWritegeneran una barrera completa al llamar al Thread.MemoryBarriermétodo, que construye una barrera de memoria que funciona en ambas direcciones. Además de las motivaciones para usar una barrera completa dadas anteriormente, un problema potencial con la volatilepalabra clave que se resuelve usando una barrera completa generada por Thread.MemoryBarrieres el siguiente: debido a la naturaleza asimétrica de las medias barreras, un volatilecampo con una instrucción de escritura seguida de Es posible que el compilador aún cambie el orden de ejecución de una instrucción de lectura. Debido a que las vallas completas son simétricas, esto no es un problema cuando se usan Thread.MemoryBarrier. [12]

En Fortrán

VOLATILEes parte del estándar Fortran 2003 , [15] aunque la versión anterior lo admitía como una extensión. Hacer que todas las variables volatileen una función también sea útil para encontrar errores relacionados con el alias .

entero , volátil :: i ! Cuando no se define volátil, las siguientes dos líneas de código son idénticas, escriba ( * , * ) i ** 2 ! Carga la variable i una vez desde la memoria y multiplica ese valor por sí mismo escribe ( * , * ) i * i ! Carga la variable i dos veces desde la memoria y multiplica esos valores        

Al "profundizar" siempre en la memoria de un VOLÁTIL, el compilador de Fortran no puede reordenar lecturas o escrituras en volátiles. Esto hace visibles para otros hilos las acciones realizadas en este hilo, y viceversa. [dieciséis]

El uso de VOLATILE reduce e incluso puede impedir la optimización. [17]

Referencias

  1. ^ ab "Publicación sobre el comité de estándares de C++".
  2. ^ Resumen de solicitud de aclaración para C11. Versión 1.13, octubre de 2017.
  3. ^ "Palabra clave volátil en Visual C++". MSDN de Microsoft .
  4. ^ "Documentación del kernel de Linux: por qué no se debe utilizar la clase de tipo" volátil "". kernel.org .
  5. ^ Scott Meyers; Andréi Alexandrescu (2004). "C++ y los peligros del bloqueo de doble verificación" (PDF) . DDJ .
  6. ^ Jeremy Andrews (2007). "Linux: superstición volátil". kerneltrap.org. Archivado desde el original el 20 de junio de 2010 . Consultado el 9 de enero de 2011 .
  7. ^ "volátil (C++)". MSDN de Microsoft .
  8. ^ Sección 17.4.4: Orden de sincronización "La especificación del lenguaje Java®, edición Java SE 7". Corporación Oráculo . 2013 . Consultado el 12 de mayo de 2013 .
  9. ^ "Simultaneidad de Java: comprensión de la palabra clave 'volátil'". dzone.com. 2021-03-08. Archivado desde el original el 9 de mayo de 2021 . Consultado el 9 de mayo de 2021 .
  10. ^ Jeremy Manson; Brian Goetz (febrero de 2004). "Preguntas frecuentes sobre JSR 133 (modelo de memoria Java)". Archivado desde el original el 9 de mayo de 2021 . Consultado el 5 de noviembre de 2019 .
  11. ^ Neil Coffey. "Bloqueo verificado dos veces (DCL) y cómo solucionarlo". Javamex . Consultado el 19 de septiembre de 2009 .
  12. ^ abcd Albahari, José. "Parte 4: subprocesos avanzados". Enhebrado en C# . Medios O'Reilly. Archivado desde el original el 12 de diciembre de 2019 . Consultado el 9 de diciembre de 2019 .{{cite web}}: Mantenimiento CS1: bot: estado de la URL original desconocido ( enlace )
  13. ^ Richter, Jeffrey (11 de febrero de 2010). "Capítulo 7: Constantes y campos". CLR a través de C# . Prensa de Microsoft. págs.183. ISBN 978-0-7356-2704-8.
  14. ^ Richter, Jeffrey (11 de febrero de 2010). "Capítulo 28: Construcciones primitivas de sincronización de subprocesos". CLR a través de C# . Prensa de Microsoft. págs. 797–803. ISBN 978-0-7356-2704-8.
  15. ^ "Declaración y atributo VOLÁTIL". Cray. Archivado desde el original el 23 de enero de 2018 . Consultado el 22 de abril de 2016 .
  16. ^ "Matriz volátil y compartida en Fortran". Intel.com .
  17. ^ "VOLÁTIL". Oracle.com .

enlaces externos