¿Se actualizan las variables globales entre las llamadas de función?

Estoy escribiendo firmware incorporado, y a veces me resulta difícil decidir cuándo necesito volátil o no.

Cuando tengo una función que espera a que se cambie una bandera booleana por una interrupción, es obvio que la bandera debe ser volátil, porque de lo contrario la función esperaría por siempre, ya que el comstackdor no se da cuenta de que el valor puede cambiarse interrumpir.

¿Pero cuando tengo una función corta que solo marca una bandera en la primera línea, espero que la bandera no tenga que ser volátil, porque su valor se leerá cada vez que ingrese la función? Entonces, cuando una interrupción modifica su valor entre la primera vez que llamo a la función y la segunda vez, obtendré el valor actual. ¿O no está garantizado que cada vez que entro en la función se borran todos los registros de almacenamiento en caché?

Aún necesitaría marcar su variable volatile : ya que el optimizador es libre para integrar sus funciones, especialmente las cortas, llamar a su función en un bucle sin una marca volatile para acceder a la memoria modificada por hardware lo pondría en peligro de no leer el Memoria después de la iteración inicial.

… porque su valor será leído cada vez que entro en la función?

No, no hay garantía para esto. El problema con la “falta de error volátil” es que el optimizador del comstackdor, sin darse cuenta de que una determinada variable puede cambiarse desde una fuente externa, cambia todo el significado del código.

Así que si tienes esto:

 static int x=0; int func (void) { if(x == 0) { return 1; } else { return 0; } } interrupt void isr (void) { x = SOMETHING; } 

Entonces el comstackdor reflexionará: “Hmm, x nunca se modifica en ninguna parte, ya que” isr “nunca se llama desde el progtwig. Entonces x siempre es 0, optimizaré el código para esto:”

 int func (void) { return 1; } 

Y entonces, tal vez, enlista toda la función. Que eso suceda o no tiene ninguna importancia, ya que el significado del código ya se destruyó en el paso de optimización anterior.

Cualquier variable compartida con una interrupción (o un subproceso, un DMA, un registro de hardware o una función de callback) debe declararse como volátil, siempre.

CUALQUIER acceso a un registro de hardware es mejor marcarlo como volátil. El comstackdor no sabe que se cambiará mediante interrupción o DMA desde el hardware y el comstackdor puede y asumirá que no lo hace, por lo que puede y almacenará en caché ciertos valores.

Esencialmente, si se asigna el hardware o se puede cambiar mediante interrupción (desde el hardware), márquelo como volátil.

Además de marcar la variable volátil para forzar una carga (como sugiere @dasblinkenlight), también debe tomar medidas para asegurarse de que la variable se lea (y escriba) de forma atómica. En algunas plataformas para ciertos objetos de tamaño (como valores de 32 bits en procesadores x86 recientes), esto sucede automáticamente. En general, es posible que deba poner un locking de sincronización alrededor de la variable, como un mutex o un semáforo. Esto es relativamente fácil de hacer cuando el código asíncrono es un hilo. No estoy seguro de qué hacer cuando hay una verdadera interrupción involucrada, ya que algunas técnicas de sincronización podrían no ser posibles. La documentación de su plataforma debe proporcionar alguna información aquí.

Toda la memoria compartida debe ser declarada volatile .

Puede o no estar en lo cierto al afirmar que su comstackdor particular no optimizará una lectura en un ejemplo particular, pero en ese caso la palabra clave volatile agrega una sobrecarga de cero (es decir, no hay una sobrecarga al especificar una lectura explícita donde iba a suceder en en cualquier caso), entonces ¿por qué arriesgarse un comportamiento indefinido o no portátil?