El calificador volátil en C

Mehvish Ashiq 12 octubre 2023
  1. el Calificador volátil en C
  2. Uso del Calificador volátil en Programación C
El calificador volátil en C

El tutorial de hoy enseña sobre el calificador volátil en C. Comprenderemos cómo y dónde podemos usar este calificador en la programación de C.

el Calificador volátil en C

No usamos el calificador volátil hasta que trabajamos en programación de bajo nivel. Aquí, la programación de bajo nivel significa el código que tiene que lidiar con los puertos IO y las rutinas de servicio de interrupción (ISR) que se supone que interactúan con el hardware.

Todos sabemos que el compilador transforma el código C en código Machine para que el archivo ejecutable pueda ejecutarse sin la disponibilidad del código fuente.

Al igual que otras tecnologías, el compilador para la programación en C también convierte el código fuente en código de máquina. Aquí, el compilador normalmente se esfuerza por optimizar el resultado (salida) para que el código de máquina mínimo deba ejecutarse al final.

Este tipo de optimización elimina el código de máquina innecesario para acceder a la variable que no se actualiza desde la perspectiva del compilador.

Código de ejemplo:

int main() {
  int status = 0;
  while (status == 0) {
  }
}

El compilador de optimización observará que la variable denominada estado no se actualiza en un bucle mientras en el código anterior. Por lo tanto, no es necesario acceder a esta variable en cada iteración.

El compilador convertiría el bucle en un bucle infinito (while(1)) para que no se requiera el código de máquina para leer la variable status.

El compilador no sabe que la variable estado también se puede actualizar en el programa actual en cualquier punto fuera del bucle. Por ejemplo, cuando se produce una operación de E/S en el dispositivo periférico.

En la práctica, queremos que el compilador tenga acceso a una variable llamada estado en cada iteración, aunque el programa no la cambie. Ahora, puede tener una sugerencia para desactivar todas las optimizaciones de compilación para tales programas C para evitar este tipo de situación, pero esa no es la solución por las siguientes razones.

  • La implementación de los compiladores varía de unos a otros.
  • Desactivar todas las optimizaciones del compilador solo por una variable puede causar problemas porque algunas de estas optimizaciones pueden ser necesarias en alguna otra parte del programa.
  • Debido a la desactivación de las optimizaciones del compilador, la aplicación de bajo nivel no puede funcionar como se suponía. Por ejemplo, retraso en la ejecución.

Aquí es donde necesitamos el calificador volátil. La palabra clave volátil no es más que un calificador que nosotros (como programadores) usamos para decirle al compilador que no se permiten optimizaciones para el estado y se usa de la siguiente manera.

volatile int status = 0;

El que utilice este calificativo debe considerar las siguientes propiedades de volátil.

  • No puede quitar la asignación de memoria.
  • Las variables no se pueden almacenar en caché en el registro.
  • El valor no se puede cambiar en el orden de la asignación.

Uso del Calificador volátil en Programación C

En el siguiente código, imprimimos un mensaje que dice "Esperando..." hasta que el hilo cambia la variable llamada hecho y luego imprimimos otro mensaje que dice "Está bien, sigamos adelante".

Código de ejemplo (sin volátil):

#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

bool done = false;

void *tfunc() {
  sleep(1);
  done = true;
  return NULL;
}

int main() {
  pthread_t t1;
  pthread_create(&t1, NULL, tfunc, NULL);
  printf("Waiting...\n");
  while (!done) {
  }
  printf("Okay, Let's move on");
}

Compile y ejecute este programa.

PS C:\Users\DelftStack\Desktop\C> gcc volatile.c -o volatile -lpthread
PS C:\Users\DelftStack\Desktop\C> ./volatile

Si observamos el siguiente resultado, las cosas normalmente van como se esperaba.

Producción :

Waiting...
Okay, Let's move on

Ahora, activamos la optimización del compilador para el mismo código fuente.

PS C:\Users\DelftStack\Desktop\C> gcc -O3 volatile.c -o volatile -lpthread
PS C:\Users\DelftStack\Desktop\C> ./volatile

No funciona como se esperaba porque muestra el resultado a continuación.

Producción :

Waiting...

El compilador observó el bucle while y notó que la variable done nunca se actualiza en el bucle while. Debido a que el compilador no se da cuenta de que otro hilo modifica la variable global llamada hecho, y esa es la razón, el compilador cambia el código por nosotros y rompe el programa.

Aquí es donde usamos el calificativo volátil. Actualizamos el código y hacemos que la variable hecho sea volátil.

Código de ejemplo (con volátil):

#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

volatile bool done = false;

void *tfunc() {
  sleep(1);
  done = true;
  return NULL;
}

int main() {
  pthread_t t1;
  pthread_create(&t1, NULL, tfunc, NULL);
  printf("Waiting...\n");
  while (!done) {
  }
  printf("Okay, Let's move on");
}

El código funciona bien incluso con las optimizaciones. Vea lo siguiente.

PS C:\Users\DelftStack\Desktop\C> gcc -O3 volatile.c -o volatile -lpthread
PS C:\Users\DelftStack\Desktop\C> ./volatile

Producción :

Waiting...
Okay, Let's move on
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook