Pregunta

¿Qué hace el volatile palabras clave hacer?En C++ ¿qué problema resuelve?

En mi caso, nunca he sabiendas necesitaba.

¿Fue útil?

Solución

volatile es necesario si usted está leyendo un lugar en la memoria que, por ejemplo, en un proceso/dispositivo/lo que sea, puede escribir.

Yo solía trabajar con doble puerto de ram en un sistema multiprocesador en la recta C.Se utilizó un hardware administrado valor de 16 bits como un semáforo para saber cuando el otro chico estaba hecho.Básicamente hicimos esto:

void waitForSemaphore()
{
   volatile uint16_t* semPtr = WELL_KNOWN_SEM_ADDR;/*well known address to my semaphore*/
   while ((*semPtr) != IS_OK_FOR_ME_TO_PROCEED);
}

Sin volatile, el optimizador ve el aro como inútil (El chico nunca se pone el valor!Él nueces, deshacerse de ese código!) y mi código de proceder sin haber adquirido el semáforo, provocando problemas en el futuro.

Otros consejos

volatile es necesaria cuando el desarrollo de sistemas embebidos o los controladores de dispositivo, donde usted necesita leer o escribir en una memoria asignada a un dispositivo de hardware.El contenido de un determinado dispositivo de registro podría cambiar en cualquier momento, por lo que necesita el volatile la palabra clave para asegurar que tales accesos no optimizado por el compilador.

Algunos procesadores tienen registros de punto flotante que tienen más de 64 bits de precisión (por ejemplo.32-bit x86 sin ESS, ver a Pedro del comentario).De esa manera, si la ejecución de varias operaciones sobre los números de precisión doble, en realidad obtiene una mayor precisión de la respuesta de si se va a truncar cada resultado intermedio a 64 bits.

Esto es generalmente grandes, pero esto significa que, dependiendo de cómo el compilador asigna los registros y del que hizo optimizaciones tendrás resultados diferentes para el mismo las operaciones en las mismas entradas.Si usted necesita consistencia a continuación, puede obligar a cada operación para volver a la memoria, el uso de la palabra clave volatile.

También es útil para algunos de los algoritmos que hacen que no algebraicas, pero a reducir de punto flotante de error, tales como Kahan suma.Algebraicly es un nop, por lo que se consigue a menudo incorrectamente optimizado menos que algunas de las variables intermedias son volátiles.

A partir de una "Volátil como una promesa" artículo de Dan Saks:

(...) la volatilidad del objeto es uno cuyo valor puede cambiar de forma espontánea.Es decir, cuando se declara un objeto a ser volátiles, le estamos diciendo al compilador que el objeto puede cambiar de estado aunque no hay declaraciones en el programa aparecen para cambiarlo".

Aquí están los enlaces a tres de sus artículos sobre la volatile palabra clave:

DEBE utilizar volátil cuando la aplicación de bloqueo libre de estructuras de datos.De lo contrario el compilador es gratuito para optimizar el acceso a la variable, que va a cambiar la semántica.

Para decirlo de otra manera, la volatilidad le dice al compilador que los accesos a esta variable debe corresponder a un físico de la memoria de lectura/escritura de la operación.

Por ejemplo, esta es la forma en InterlockedIncrement se declara en la API de Win32:

LONG __cdecl InterlockedIncrement(
  __inout  LONG volatile *Addend
);

Una gran aplicación que he utilizado para trabajar en la en la década de 1990 figura C-excepción basada en el manejo de uso de setjmp y longjmp.La palabra clave volatile era necesario en las variables cuyos valores necesarios para ser conservado en el bloque de código que sirve como la "captura" de la cláusula, para que los revendedores se almacenan en registros y aniquilada por la longjmp.

En el Estándar de C, uno de los lugares para utilizar volatile es un manejador de señal.De hecho, en el nivel C, todo lo que usted puede hacerlo de forma segura en un manejador de señal es modificar un volatile sig_atomic_t variable, o salir rápidamente.De hecho, AFAIK, es el único lugar en el Estándar de C que el uso de volatile es necesario para evitar un comportamiento indefinido.

ISO/IEC 9899:2011 §7.14.1.1 La signal la función

¶5 Si la señal se produce de otra manera que como el resultado de llamar a la abort o raise la función, la el comportamiento no está definido si el manejador de señal se refiere a cualquier objeto estático o hilo el tiempo de almacenamiento que no es un cierre libre atómica objeto que no sea mediante la asignación de un valor a un objeto declarado como volatile sig_atomic_t, o el controlador de señal de llama para cualquier función en la biblioteca estándar de otros de la abort la función, la _Exit la función, la quick_exit la función, o la signal función con el primer argumento igual a la número de señal correspondiente a la señal que causó la invocación del controlador.Además, si la llamada a la signal los resultados de la función en un SIG_ERR de retorno, la valor de errno es indeterminada.252)

252) Si la señal es generada por una asincronía en el manejador de señal, el comportamiento es indefinido.

Eso significa que en el Estándar de C, podemos escribir:

static volatile sig_atomic_t sig_num = 0;

static void sig_handler(int signum)
{
    signal(signum, sig_handler);
    sig_num = signum;
}

y no mucho más.

POSIX es mucho más indulgente sobre lo que usted puede hacer en un manejador de señal, pero todavía hay limitaciones (y una de las limitaciones es que el Estándar de e/S de la biblioteca — printf() et al — no se puede utilizar de forma segura).

El desarrollo de una incrustado, tengo un bucle que se comprueba en una variable que puede ser cambiado en un controlador de interrupciones.Sin "volátil", el bucle se convierte en un noop - tan lejos como el compilador puede decir, que la variable no cambia nunca, por lo que se optimiza la verificación de distancia.

Lo mismo se podría aplicar a una variable que puede ser cambiado en un subproceso diferente en un ambiente más tradicional, pero no hacemos a menudo la sincronización de llamadas, por lo que el compilador no es tan libre con la optimización.

Lo he utilizado en las versiones de depuración cuando el compilador se insiste en la optimización de distancia una variable que quiero ser capaz de ver como me paso a través del código.

Además de usarlo como se pretende, la volatilidad se utiliza en (plantilla) metaprogramación.Puede ser usado para prevenir la sobrecarga accidental, como la volatilidad de atributo (como const) toma parte en la resolución de sobrecarga.

template <typename T> 
class Foo {
  std::enable_if_t<sizeof(T)==4, void> f(T& t) 
  { std::cout << 1 << t; }
  void f(T volatile& t) 
  { std::cout << 2 << const_cast<T&>(t); }

  void bar() { T t; f(t); }
};

Esto es legal;tanto las sobrecargas son potencialmente puede llamar y hacer casi de la misma.El elenco de la volatile la sobrecarga es legal como sabemos barra de no pase de un no-volátil T de todos modos.El volatile la versión es estrictamente peor, aunque, por lo que nunca elegido en la resolución de sobrecarga si el no-volátil f está disponible.

Tenga en cuenta que el código nunca en realidad, depende de volatile acceso a la memoria.

  1. usted debe usarlo para implementar spinlocks así como algunos (todos?) libre de bloqueo de estructuras de datos
  2. utilizar con operaciones atómicas/instrucciones
  3. me ayudó una vez a superar compilador del error (erróneamente el código generado durante la optimización)

El volatile palabra clave es la intención de evitar que el compilador de la aplicación de alguna optimizaciones en los objetos que pueden cambiar en formas que no pueden ser determinados por el compilador.

Los objetos declarados como volatile se omiten de optimización debido a que sus valores pueden ser modificados por el código fuera del ámbito de aplicación del código actual en cualquier momento.El sistema siempre se lee el valor actual de un volatile objeto de la ubicación de la memoria en lugar de mantener su valor en el registro temporal en el punto en el que se solicita, incluso si una instrucción anterior se le preguntó por un valor desde el mismo objeto.

Considere los siguientes casos

1) las variables Globales modificada por una rutina de servicio de interrupción fuera del ámbito de aplicación.

2) variables Globales dentro de una aplicación multiproceso.

Si no utilizamos volátiles calificador, los problemas que pueden surgir

1) Código no funcione como se esperaba cuando optimización está activado.

2) Código no funcione como se esperaba cuando las interrupciones están habilitadas y utilizado.

Volátil:Un programador es el mejor amigo del

https://en.wikipedia.org/wiki/Volatile_(computer_programming)

Además del hecho de que la palabra clave volatile se utiliza para decirle al compilador no para optimizar el acceso a una variable (que puede ser modificada por un hilo o una rutina de interrupción), puede ser también se utiliza para eliminar algunos errores de compilador -- SÍ se puede ---.

Por ejemplo, yo trabajé en una plataforma embebida fueron el compilador estaba haciendo algunos mal assuptions con respecto a un valor de una variable.Si el código no optimizado que el programa se ejecute aceptar.Con las optimizaciones (que eran realmente necesarias, ya que fue un crítico de rutina) el código no funciona correctamente.La única solución (aunque no es muy correcto) fue declarar la 'defectuoso' variable como volátil.

El programa parece funcionar incluso sin volatile palabra clave?Tal vez esta es la razón:

Como se mencionó anteriormente, el volatile palabra clave ayuda para casos como

volatile int* p = ...;  // point to some memory
while( *p!=0 ) {}  // loop until the memory becomes zero

Pero parece ser que casi no tienen efecto una vez que un externo o no en línea función es la de ser llamado.E. g.:

while( *p!=0 ) { g(); }

A continuación, con o sin volatile casi el mismo resultado se genera.

Mientras g() puede ser completamente en línea, el compilador puede ver todo lo que está pasando y por lo tanto puede optimizar.Pero cuando el programa hace una llamada a un lugar donde el compilador no puede ver lo que está pasando, no es seguro para el compilador de hacer suposiciones más.Por lo tanto, el compilador generará un código que siempre se lee de la memoria directamente.

Pero ten cuidado, día, cuando su función g() se convierte en línea (ya sea debido a lo explícito de los cambios o debido al compilador/enlazador de la inteligencia), a continuación, el código podría romperse si usted se olvidó de los volatile palabra clave!

Por lo tanto, recomiendo agregar el volatile palabra clave, incluso si su programa parece funcionar sin.Esto hace que la intención más clara y más robusto con respecto a los cambios del futuro.

En los primeros días de C, compiladores podría interpretar todas las acciones que leer y escribir lvalues como las operaciones de la memoria, a realizarse en la misma secuencia que la lee y escribe apareció en el código.La eficiencia podría ser mejorado en gran medida, en muchos casos, si los compiladores se le da una cierta cantidad de libertad para re-ordenar y consolidar sus operaciones, pero hubo un problema con esto.Incluso las operaciones eran a menudo se especifican en un orden determinado, simplemente porque era necesario especificar en algunos orden, y por lo tanto el programador elegido uno de los muchos igualmente buenas alternativas, que no era siempre el caso.A veces sería importante que ciertas operaciones se producen en una secuencia particular.

Exactamente lo que los detalles de secuenciación son importantes van a variar dependiendo de la plataforma objetivo y campo de aplicación.En lugar de proporcionar detallados en particular, el control, la Norma ha optado por un modelo simple:si una secuencia de accesos se realizan con lvalues que no están cualificados volatile, un compilador puede reorganizar y consolidar en ellos como lo considere oportuno.Si una acción se realiza con un volatile-calificados lvalue, una aplicación de la calidad debe ofrecer las otras garantías de orden puede ser requerido por el código de la orientación de su intención de plataforma y campo de aplicación, sin tener que requieren el uso de la no-estándar de sintaxis.

Por desgracia, en lugar de identificar lo que garantiza a los programadores que necesitan, muchos compiladores han optado en lugar de ofrecer las mínimas garantías exigidos por la Norma.Esto hace que volatile mucho menos útil de lo que debería ser.En gcc o clang, por ejemplo, un programador que necesitan para implementar una base "hand-off mutex" [uno donde una tarea que ha adquirido y puesto en libertad un mutex no hacerlo de nuevo hasta que el otro lo ha hecho] debe hacer una de cuatro cosas:

  1. Poner la adquisición y liberación de la exclusión mutua en función de que el compilador no puede en línea, y a la que no se puede aplicar Todo el Programa de Optimización.

  2. Calificar a todos los objetos custodiados por el mutex como volatile- algo que no debería ser necesario si todos los accesos se producen después de adquirir el mutex y antes de soltarlo.

  3. Optimización del uso de nivel 0 para forzar al compilador que genere código como si todos los objetos que no están calificados register son volatile.

  4. Usar gcc-directivas específicas.

Por el contrario, cuando se utiliza una mayor calidad compilador que es más adecuado para la programación de sistemas, tales como la cpi, uno tendría otra opción:

  1. Asegúrese de que un volatile-calificados escribir consigue realizar cualquier lugar una adquisición o de liberación es necesario.

La adquisición de una base "hand-off mutex" requiere de un volatile leer (a ver si es listo), y no requieren de un volatile escribir tan bien (el otro lado no voy a tratar de volver a adquirir hasta que sea entregada de nuevo), pero tener que realizar un sin sentido volatile escribir es mejor que cualquiera de las opciones disponibles en gcc o clang.

Uno de los usos que debo recordarle que usted es, en la señal de función del controlador, si desea acceder/modificar una variable global (por ejemplo, marca como salir = true) usted tiene que declarar la variable como "volátil".

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top