¿Cuál es la diferencia entre una variable global estática y una variable volátil estática?

StackOverflow https://stackoverflow.com/questions/346306

Pregunta

He usado una variable global estática y una variable volátil estática en el alcance del archivo,

ambos son actualizados por un ISR y un bucle principal y un bucle principal verifican el valor de la variable.

aquí durante la optimización, ni la variable global ni la variable volátil están optimizadas. Entonces, en lugar de usar una variable volátil, una variable global resuelve el problema.

Entonces, ¿es bueno usar variable global en lugar de volátil?

¿Alguna razón específica para usar volátiles estáticos?

Cualquier programa de ejemplo sería apreciable.

Gracias de antemano ..

¿Fue útil?

Solución

Son cosas diferentes. No soy un experto en semántica volátil. Pero creo que tiene sentido lo que se describe aquí.

Global

Global solo significa que el identificador en cuestión se declara en el ámbito del archivo. Existen diferentes ámbitos, llamados función (donde se definen goto-etiquetas), & # 64257; le (donde residen los globales), bloque (donde residen las variables locales normales) y prototipo de función (donde residen los parámetros de la función). Este concepto solo existe para estructurar la visibilidad de los identificadores. No tiene nada que ver con las optimizaciones.

Estático

static es una duración de almacenamiento (no veremos eso aquí) y una forma de dar un nombre declarado dentro del enlace interno del alcance del archivo. Esto se puede hacer para funciones u objetos que solo se requieren dentro de una unidad de traducción. Un ejemplo típico podría ser una función help que imprime los parámetros aceptados, y que solo se llama desde la función main definida en el mismo .c expediente.

6.2.2 / 2 en un borrador de C99:

  

Si la declaración de un & # 64257; le alcance   identificador & # 64257; er para un objeto o una función   contiene la especificación de clase de almacenamiento & # 64257; er   estática, el identificador & # 64257; er tiene interna   enlace.

Enlace interno significa que el identificador no es visible fuera de la unidad de traducción actual (como la función help de arriba).

Volátil

Volátil es una cosa diferente: ( 6.7.3 / 6 )

  

Un objeto que tiene volatile-quali & # 64257; ed   tipo puede modificarse & # 64257; ed en formas desconocidas para   la implementación o tener otro   efectos secundarios desconocidos Por lo tanto, cualquier   expresión que se refiere a tal objeto   será evaluado estrictamente de acuerdo   a las reglas de la máquina abstracta,   como se describe en 5.1.2.3. Además,   en cada punto de secuencia el último valor   almacenado en el objeto deberá estar de acuerdo con   lo prescrito por el resumen   máquina, excepto como modi & # 64257; ed por el   factores desconocidos mencionados   anteriormente.

El Estándar proporciona un excelente ejemplo para un ejemplo donde volátil sería redundante ( 5.1.2.3/8 ):

  

Una implementación podría de & # 64257; ne a   correspondencia uno a uno entre   semántica abstracta y actual: en   cada punto de secuencia, los valores de   los objetos reales estarían de acuerdo con   aquellos especi & # 64257; ed por el resumen   semántica. La palabra clave volátil   entonces sería redundante.

Los puntos de secuencia son puntos en los que se completa el efecto de los efectos secundarios relacionados con la máquina abstracta (es decir, no se incluyen condiciones externas como los valores de las celdas de memoria). Entre la derecha y la izquierda de & amp; & amp; y || , después de ; y al regresar de una llamada de función hay puntos de secuencia, por ejemplo.

La semántica abstracta es lo que el compilador puede deducir al ver solo la secuencia de código dentro de un programa en particular. Los efectos de las optimizaciones son irrelevantes aquí. La semántica real incluye el efecto de los efectos secundarios al escribir en objetos (por ejemplo, cambio de celdas de memoria). Calificar un objeto como volátil significa que siempre se obtiene el valor de un objeto directamente de la memoria ("modificado por los factores desconocidos"). El Estándar no menciona subprocesos en ninguna parte, y si debe confiar en el orden de los cambios o en la atomicidad de las operaciones, debe usar formas dependientes de la plataforma para asegurarse de eso.

Para obtener una descripción general fácil de entender, Intel tiene un excelente artículo al respecto aquí .

¿Qué debo hacer ahora?

Siga declarando sus datos de alcance de archivo (global) como volátiles. Datos globales i

Otros consejos

Primero permítanme mencionar que una variable global estática, es lo mismo que una variable global, excepto que está limitando la variable al alcance del archivo. Es decir. no puede usar esta variable global en otros archivos mediante la palabra clave extern .

Para que pueda reducir su pregunta a variables globales versus variables volátiles.

Ahora en volátil:

Al igual que const , volátil es un modificador de tipo.

La palabra clave volátil se creó para evitar optimizaciones del compilador que pueden hacer que el código sea incorrecto, específicamente cuando hay eventos asincrónicos.

Los

objetos declarados como volátiles no pueden usarse en ciertas optimizaciones.

El sistema siempre lee el valor verdadero actual de un objeto volátil en el punto en el que se utiliza, incluso si una instrucción anterior solicitaba un valor del mismo objeto. Además, el valor del objeto se escribe inmediatamente en la asignación. Eso significa que no hay almacenamiento en caché de una variable volátil en un registro de CPU.

Dr. Jobb's tiene un excelente artículo sobre volátil .

Aquí hay un ejemplo del artículo del Dr. Jobb:

class Gadget
{
public:
    void Wait()
    {
        while (!flag_)
        {
            Sleep(1000); // sleeps for 1000 milliseconds
        }
    }
    void Wakeup()
    {
        flag_ = true;
    }
    ...
private:
    bool flag_;
};

Si el compilador ve que Sleep () es una llamada externa, asumirá que Sleep () no puede cambiar el valor de la variable flag_. Por lo tanto, el compilador puede almacenar el valor de flag_ en un registro. Y en ese caso, nunca cambiará. Pero si otro subproceso llama a la activación, el primer subproceso todavía está leyendo desde el registro de la CPU. Wait () nunca se activará.

Entonces, ¿por qué no simplemente nunca almacenar en caché las variables en los registros y evitar el problema por completo? Resulta que esta optimización realmente puede ahorrarle mucho tiempo en general. Entonces, C / C ++ le permite deshabilitarlo explícitamente a través de la palabra clave volátil .

El hecho anterior de que flag_ era una variable miembro, y no una variable global (ni global estática) no importa. La explicación después del ejemplo proporciona el razonamiento correcto incluso si se trata de variables globales (y variables globales estáticas).

Una idea errónea común es que declarar una variable volátil es suficiente para garantizar la seguridad del hilo. Las operaciones en la variable aún no son atómicas, a pesar de que no están "en caché" en registros

volátil con punteros:

Volátil con punteros, funciona como constante con punteros.

Una variable de tipo volatile int * significa que la variable a la que apunta el puntero es volátil.

Una variable de tipo int * volatile significa que el puntero en sí es volátil.

El " volátil " la palabra clave sugiere que el compilador no haga ciertas optimizaciones en el código que involucra esa variable; si solo usa una variable global, nada impide que el compilador optimice incorrectamente su código.

Ejemplo:

#define MYPORT 0xDEADB33F

volatile char *portptr = (char*)MYPORT;
*portptr = 'A';
*portptr = 'B';

Sin " volátil " ;, la primera escritura puede optimizarse.

La palabra clave volátil le dice al compilador que se asegure de que la variable nunca será almacenada en caché. Todos los accesos a él deben hacerse de manera consistente para tener un valor consistente entre todos los hilos. Si el valor de la variable se va a cambiar por otro subproceso mientras tiene un bucle buscando cambios, desea que la variable sea volátil ya que no hay garantía de que un valor de variable regular no se almacene en caché en algún momento y el bucle asumirá que se mantiene igual.

Variable volátil en Wikipedia

Puede que no sean diferentes en su entorno actual, pero cambios sutiles podrían afectar el comportamiento.

  • Hardware diferente (más procesadores, arquitectura de memoria diferente)
  • Una nueva versión del compilador con mejor optimización.
  • Variación aleatoria en el tiempo entre hilos. Un problema solo puede ocurrir una vez en 10 millones.
  • Diferentes configuraciones de optimización del compilador.

Es mucho más seguro a largo plazo utilizar construcciones multiproceso adecuadas desde el principio, incluso si las cosas parecen funcionar por ahora sin ellas.

Por supuesto, si su programa no es multiproceso, entonces no importa.

I +1 la respuesta de friol. Me gustaría agregar algunas precisiones, ya que parece haber muchas confusiones en diferentes respuestas: la volatilidad de C no es la volátil de Java.

Entonces, primero, los compiladores pueden hacer muchas optimizaciones basadas en el flujo de datos de su programa, lo volátil en C evita eso, se asegura de que realmente cargue / almacene en la ubicación cada vez (en lugar de usar registros de limpieza) fuera, por ejemplo). Es útil cuando tiene un puerto IO mapeado de memoria, como lo señaló friol.

Volátil en C no tiene nada que ver con cachés de hardware o multihilo. No inserta vallas de memoria, y no tiene absolutamente ninguna garantía sobre el orden de las operaciones si dos hilos acceden a ella. Sin embargo, la palabra clave volátil de Java hace exactamente eso: insertar vallas de memoria donde sea necesario.

variable volátil significa que el valor asignado no es constante, es decir, si una función que contiene una variable volátil " a = 10 " y la función agrega 1 en cada llamada de esa función, siempre devolverá un valor actualizado. { volátil int a = 10; a ++; } cuando se llama a la función anterior una y otra vez, la variable a no se reinicializará a 10, siempre mostrará el valor actualizado hasta que se ejecute el programa. Primera salida = 10 entonces 11 entonces 12 y así sucesivamente.

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