transacciones sinonimo economia distribuidas datos consistencia atomicidad aislamiento c atomic volatile

sinonimo - transacciones base de datos



Si la volatilidad no sirve para el enhebrado, ¿por qué las operaciones atómicas requieren punteros a los datos volátiles? (4)

He estado leyendo de muchas fuentes que la palabra clave volatile no es útil en escenarios de multiproceso . Sin embargo, esta afirmación es desafiada constantemente por las funciones de operación atómica que aceptan punteros volatile .

Por ejemplo, en Mac OS X, tenemos la familia de funciones OSAtomic :

SInt32 OSIncrementAtomic(volatile SInt32 *address); SInt32 OSDrecrementAtomic(volatile SInt32 *address); SInt32 OSAddAtomic(SInt32 amount, volatile SInt32 *address); // ...

Y parece que hay un uso similar de la palabra clave volatile en Windows para las operaciones de Interlocked :

LONG __cdecl InterlockedIncrement(__inout LONG volatile *Addend); LONG __cdecl InterlockedDecrement(__inout LONG volatile *Addend);

También parece que en C ++ 11, los tipos atómicos tienen métodos con el modificador volatile , lo que de alguna manera debe significar que la palabra clave volatile tiene algún tipo de relación con la atomicidad.

Entonces, ¿qué me estoy perdiendo? ¿Por qué los proveedores de sistemas operativos y los diseñadores de bibliotecas estándar insisten en usar la palabra clave volatile para propósitos de subprocesamiento si no es útil?


Bueno, la palabra clave ''volátil'' asegura que el compilador siempre carga / almacena el valor de una variable desde / a la memoria cada vez que la variable aparece en su código.
Esto evita ciertas optimizaciones, por ejemplo, que el valor simplemente se carga en un registro una vez y luego se usa varias veces.
Es útil cuando tiene varios subprocesos que pueden modificar las variables ''compartidas'' entre los subprocesos. Deberá asegurarse de siempre cargar / almacenar el valor de / en la memoria para verificar su valor que puede haber sido modificado por otro hilo. Si no se usó volatile, el otro subproceso podría no haber escrito el nuevo valor en la memoria (pero ponerlo en un registro u otro tipo de optimización podría haber tenido lugar) y el primer subproceso no notaría ningún cambio de valor.

En sus casos, la ''dirección SInt32 * volátil'' le dice al compilador que la memoria apuntada por dirección está sujeta a cambios por cualquier fuente. De ahí la necesidad de una operación atómica.


C ++ 11 tiene atomics tanto para variables volatile como no volatile .

Si los intrínsecos del compilador llevan un puntero a volatile int , eso significa que puede usarlo incluso si la variable es volátil. No le impide utilizar la función en datos no volatile .


De repente me di cuenta de que simplemente malinterpreté el significado de volatile* . Al igual que const* significa que el pointee no debe cambiar, volatile* significa que el pointee no debe ser almacenado en caché en un registro. Esta es una restricción adicional que se puede agregar libremente: tanto como puede lanzar un char* a un const char* , puede lanzar un int* a un volatile int* .

Por lo tanto, aplicar el modificador volatile a las puntas simplemente asegura que las funciones atómicas se puedan usar en variables ya volatile . Para las variables no volátiles, agregar el calificador es gratis. Mi error fue interpretar la presencia de la palabra clave en los prototipos como un incentivo para usarla en lugar de como una conveniencia para quienes la usan.


La volatilidad no es inútil para el acceso compartido por múltiples subprocesos, es solo que no es necesariamente suficiente:

  • no necesariamente proporciona la semántica de barrera de memoria que podría ser necesaria;
  • no proporciona garantías de acceso atómico (por ejemplo, si el objeto volátil es más grande que el tamaño de palabra de la memoria nativa de la plataforma)

Además, también debe tener en cuenta que el calificador volatile en los argumentos de puntero a las API en su ejemplo realmente solo agrega la capacidad de las API para recibir punteros a objetos volatile sin queja, no es necesario que los punteros apunten a volatile real. objetos. El estándar permite que un puntero no calificado se convierta automáticamente en un puntero calificado. Ir de forma automática hacia el otro lado (puntero calificado a no calificado) no se incluye en el estándar (los compiladores generalmente lo permiten, pero emiten una advertencia).

Por ejemplo, si InterlockedIncrement() fue prototipado como:

LONG __cdecl InterlockedIncrement(__inout LONG *Addend); // not `volatile*`

La API todavía podría implementarse para funcionar adecuadamente internamente. Sin embargo, si el usuario tenía un objeto volátil que quería pasar a la API, se requeriría un lanzamiento para evitar que el compilador lance una advertencia.

Dado que (necesario o no), estas API se usan a menudo con objetos calificados volatile , agregar el calificador volatile al argumento del puntero evita que se generen diagnósticos inútiles cuando se usa la API, y no perjudica nada cuando la API se usa con un puntero a un Objeto no volátil.