cpp-variables-volatile

Variables volatile en C++

En C++, la palabra clave volatile es un modificador de tipo que indica al compilador que el valor de una variable puede cambiar en cualquier momento (y sin que el compilador pueda preverlo).

El compilador, al optimizar el código, asume que el valor de una variable no cambia fuera de las instrucciones que la afectan directamente en el código fuente (que son las que el compilador controla).

Esto puede llevarle a hacer ciertas optimizaciones, como guardar en caché el valor de la variable o elimine accesos innecesarios.

En una variable declarada con el modificador volatile le estamos diciendo al compilador que no debe realizar ciertas optimizaciones cuanto trabaje con esa variable.

Esto es útil cuando el valor de la variable puede cambiar inesperadamente. Por ejemplo debido a:

  • Acceso a Hardware: Cuando se interactúa directamente con registros de hardware, el valor de estos registros puede cambiar en cualquier momento debido a eventos externos.
  • Multihilo: En aplicaciones multihilo, una variable compartida entre hilos puede ser modificada por uno de los hilos en cualquier momento
  • Interrupciones: Las interrupciones también pueden alterar el valor de una variable de forma inesperada.

Cómo usar volatile

Para declarar una variable como volatile, simplemente añades el modificador volatile en la declaración de la variable:

volatile int myVar;

En esta declaración, myVar es una variable que puede ser modificada en cualquier momento por factores externos a su uso en el código.

Ejemplo de uso en acceso a hardware

Un caso típico de uso de volatile es cuando se interactúa con registros de hardware en programación de sistemas embebidos. Vamos a verlo con un ejemplo sencillo:

Supongamos que tenemos una máquina que tiene un bucle while() para hacer una espera hasta que alguien pulse un botón.

#include <iostream>

// Variable simulando un registro de hardware (modificado por hardware externo)
volatile bool botonPresionado = false;

void verificarBoton() {
    while (!botonPresionado) {
        // Espera activa: el programa se queda aquí hasta que el botón sea presionado
    }
    std::cout << "¡Botón presionado!" << std::endl;
}

int main() {
    std::cout << "Esperando que se presione el botón..." << std::endl;

    // Simular que el hardware presiona el botón después de un tiempo
    botonPresionado = true;

    verificarBoton();

    return 0;
}
  • Sin volatile: El compilador podría optimizar el bucle while (!botonPresionado) asumiendo que botonPresionado nunca cambia, porque no ve ninguna modificación en el programa principal (Esto haría que el programa nunca salga del bucle).
  • Con volatile: El compilador siempre verifica el valor real de botonPresionado desde la memoria, asegurando que detecte los cambios hechos por hardware externo.

Limitaciones y consideraciones

El modificador volatile está soportado por los estándares C++ desde sus primeras versiones y sigue siendo relevante en programación a nivel de hardware y en sistemas embebidos.

Pero en aplicaciones modernas, sobre todo en programación multihilo, suelen ser preferibles std::atomic (y otras primitivas de sincronización) para manejar variables compartidas y sincronización segura entre hilos.