2012-02-20 28 views
15

Actualmente estoy leyendo el código PostgreSql. He aquí un extracto de la gestión de memoria intermedia:Por qué marcar el argumento de función como volátil

static void WaitIO(volatile BufferDesc *buf); 
static bool StartBufferIO(volatile BufferDesc *buf, bool forInput); 
static void TerminateBufferIO(volatile BufferDesc *buf, bool clear_dirty, 

sé la palabra clave volátil se utiliza generalmente para los controladores de dispositivos y en sistemas embebidos. Hay una explicación de la palabra clave.

Cuando se utiliza la palabra clave volátil en la definición de tipo, se está dando una indicación al compilador sobre cómo debe manejar la variable. Principalmente le dice al compilador que el valor de la variable puede cambiar en cualquier momento como resultado de acciones externas al programa o la línea de ejecución actual. (Source)

¿Por qué son ciertos argumentos de las funciones declaradas como volátil? No espero que DMA cambie la ubicación del puntero. Entonces, ¿qué pasa aquí?

+0

No estoy seguro de que vale la pena otra pregunta, pero interesado en saber por qué es posible escribir 'func vacío (int arg volátil);' – ideasman42

Respuesta

16

volatile BufferDesc *buf significa que los datos que bufpuntos a es volátil, no es que el puntero contenida por buf es volátil. (Eso sería BufferDesc * volatile buf.)

De the page you linked to:

Por otro lado, si usted tiene una variable puntero donde la dirección en sí era inestable pero la memoria apuntada no era entonces tenemos:

int * volatile x; 

actualización: lo siento, se perdió esta parte de su pregunta:

Entonces, ¿por qué ciertos argumentos de funciones se declaran como volátiles?

Presumiblemente porque los datos que señala pueden cambiar de una manera que el compilador no necesariamente conocería. La palabra clave volatile está ahí para evitar que el compilador aplique optimizaciones que asuman que los datos no cambian de formas que desconoce.

+0

Si el problema era una cuestión de concurrencia, la variable habría sido protegido con un mutex, por ejemplo. La palabra clave volátil solicita al compilador que evite las optimizaciones relacionadas con esa variable. Por lo tanto, lo volverá a cargar de memoria cada vez que se lea en el programa. Lo cual es necesario cuando un controlador de dispositivo acaba de terminar de escribir contenido en el búfer de memoria. TerminateBufferIO() podría ser la devolución de llamada invocada cuando el dispositivo está listo. Las palabras clave volátiles ayudan a imponer la carga del contenido desde la memoria y no solo desde el nivel de caché (que podría no estar actualizado). –

+0

¿Le gustaría al votante favorito compartir algunos comentarios útiles? –

7

No espero que DMA cambie la ubicación del puntero.

No es la ubicación, pero tal vez el contenido. Y eso es exactamente lo que se trata ...

0

DMA no es la única razón para usar "volátil". También es útil para aplicaciones de multiproceso y memoria compartida, donde otro hilo puede cambiar la memoria a la que hace referencia este código. Estoy seguro de que PostgreSql tiene varios subprocesos, por lo que esta es una posible razón por la cual se está utilizando volátil aquí.

+0

Usar volátiles para problemas de hilo es pedirlo. Debería utilizar una primitiva de hilo para la sincronización en ese caso. –

+0

El hecho de que usted ha utilizado un mutex para proteger contra condiciones de carrera no significa que el compilador no va a tratar de optimizar su acceso a las variables compartidas. Dicho esto, las primitivas de sincronización son llamadas a funciones, y el compilador no puede hacer suposiciones sobre cambios a variables no locales en torno a una llamada de función. Entonces, en general, tienes razón. –

+0

Lo que pasa es volátil en C que no hacer lo que crea volátil hace desde una perspectiva multi-threading a menos que el equipo tiene una CPU con un núcleo. Así que es rara vez son útiles en los dispositivos modernos, e incluso si es para un dispositivo dado, que no es muy compatible hacia delante, como la próxima generación de este dispositivo puede cambiar a varios núcleos. –

1

La implementación de las bases de datos no depende de los búferes del sistema operativo & cachés cuando se accede a los archivos. Prefieren implementar su propio sistema de caché y obtener acceso directo al archivo en el disco físico, por problemas de confiabilidad: los datos DEBEN ser descargados al disco físico. (Usan la opción O_DIRECT para realizar acceso directo al disco físico.)

las 3 funciones que nos está mostrando me hacen pensar en la manipulación asíncrona de datos procedentes del disco. (StartBufferIO(), TerminatedBufferIO() y así sucesivamente). La verdad es que no estoy seguro de lo que es su propósito, pero en base a lo que sé sobre la implementación de bases de datos y los nombres de función, yo diría que el contenido del buffer puede ser modificado por el "disco" en sí con los datos del archivo en el disco (o cualquier dispositivo), y por lo tanto necesita ser Flaged como volátil.

Esta hipótesis se une a su interpretación habitual de la palabra clave volátil por lo general se utiliza para: controladores de dispositivo.

0

Una cosa que un compilador suele hacer cuando la optimización es la eliminación de código muerto, así que si usted hace algunas operaciones con una variable que su nunca ha leído ninguno y su resultado es compilador inútil será probablemente sólo eliminarlo, así como la eliminación del resto de operaciones que lo afectan Ese comportamiento puede ser muy molesto cuando depura un código o estás realizando algún tipo de benchamrks. Si declara una variable volátil, alerta al compilador y podría ser utilizada por bibliotecas o programas externos, entre otras implicaciones que pueda tener la palabra clave. Entonces nunca debería tratarlo como código muerto.

Cuestiones relacionadas