2009-06-30 21 views
5

Al pasar por muchos recursos en la programación multiproceso, generalmente aparece una referencia al especificador volátil. Está claro que el uso de esta palabra clave no es una forma confiable de lograr la sincronización entre varios hilos al menos en C/C++ y Java (versiones 1.4 y anteriores). Aquí es lo que las listas de wikipedia (sin explicar cómo) usos típicos de este especificador: -Uso del especificador volátil en C/C++/Java

  1. permitir el acceso a los dispositivos de memoria mapeada
  2. permiten usos de las variables entre setjmp y longjmp
  3. permiten usos de las variables en la señal manipuladores
  4. ocupado esperando

puedo empezar a ver el papel de este especificador de los usos mencionados anteriormente, pero ya que aún no tienen una understandi completa ng de cada una de estas áreas, no puedo entender cómo se comporta exactamente este especificador en cada uno de estos usos.

¿Podría alguien explicar?

+0

Gracias por las respuestas. ¿Alguna información sobre cómo funciona exactamente la volatilidad en los usos enumerados anteriormente? – Ankur

Respuesta

6

Como le interesan estos casos de uso, le explicaré el primero. Tenga en cuenta que esto se aplica desde una perspectiva c/C++, no estoy seguro de cómo funciona en Java, aunque sospecho que en general volátil en c/C++ y java se utilizan para casos completamente diferentes.

Los dispositivos de memoria mapeada son periféricos con los que el procesador se comunica de la misma manera que la memoria en lugar de a través de un bus especial.

Supongamos que tiene un poco de luz con un temporizador que está mapeado en la memoria. Enciende la luz escribiendo 1 en su dirección de memoria & su temporizador interno cuenta regresivamente durante 5 segundos & apaga la luz y restablece la ubicación de la memoria a 0. Ahora estás desarrollando un programa de CA que necesita encender esa luz después de ciertos eventos y, a veces, apáguelo antes de que caduque el contador. Si utiliza una variable regular (tiende a ser un puntero o una referencia para este tipo de aplicación) para escribir en su ubicación de memoria, hay varias cosas que pueden salir mal debido a las optimizaciones del compilador.

Si no está trabajando con tantas variables y está encendiendo la luz y luego de apagarla sin ninguna otra variable que use ese valor, a veces el compilador se deshará por completo de la primera asignación, o en en otros casos, simplemente mantendrá el valor en los registros del procesador & nunca escriba en la memoria. En ambos casos, la luz nunca se encenderá ya que su memoria nunca se modificó.

Ahora piense en otra situación donde compruebe el estado de la luz & está encendido. Aquí, el valor se extrae de la memoria del dispositivo & guardada en un registro del procesador. Ahora, después de unos segundos, la luz se apaga sola. Poco después, intenta encender nuevamente la luz, sin embargo, desde que leyó que la dirección de la memoria & no lo ha cambiado, el compilador asume que el valor sigue siendo uno & por lo que nunca lo cambia, aunque actualmente es 0.

Al usar la palabra clave volátil, evita que el compilador haga cualquiera de estas suposiciones al convertir su código en el código de máquina &, asegura que todas esas operaciones específicas se realicen estrictamente según lo escrito por el programador. Esto es esencial para dispositivos mapeados en memoria principalmente porque el procesador no cambia la ubicación de la memoria estrictamente. Por estas mismas razones, los sistemas multiprocesador con memoria compartida a menudo requieren prácticas similares cuando se opera en un espacio de memoria común.

+0

Gracias DB. Muy buen ejemplo. – Ankur

2

Hay una buena explicación aquí: http://en.wikipedia.org/wiki/Volatile_variable pero un poco simplificada le dice al compilador que no debe suponer que la variable no es accedida por otra persona y que es fatal optimizarla en un registrador y actualizar solo el registro y no el almacenamiento real.

+0

Es diferente en C y C++ que en Java, o sorprendentemente. por ejemplo, en Java, si el compilador puede determinar que un único volátil solo tiene acceso a un elemento volátil, puede tratarse como si no fuera volátil. –

+0

Correcto, creo que también lo mencionan en la wikipedia. Sin embargo, el propósito del especificador sigue siendo más o menos el mismo. – Fredrik

-1

La variable volátil debe usarse cuando muchos subprocesos pueden acceder a esa variable y desea que en cada instrucción su código obtenga el valor actualizado de esa variable.

Los compiladores generalmente optimizan el código y almacenan variables en el registro en lugar de obtener de la memoria todas y cada una de las veces si ven que nadie lo ha actualizado.

Pero al usar volátiles puede obligar al compilador a obtener el valor actualizado todo el tiempo.

+1

Esto no es correcto. 'volátil' es simplemente decirle al compilador que "algo fuera de tu control puede modificar esta variable, así que no la optimices". Realmente no tienes otras garantías con respecto a lo que sucederá. Los enlaces en las otras respuestas explican por qué es incorrecto usar 'volátil' como usted describe. –

+0

Considere cachés de CPU. La máquina abstracta C no conoce los cachés de la CPU. Para ello, un valor puede estar en almacenamiento si solo está en la memoria caché de la CPU * one *, por ejemplo. Para aplicaciones de múltiples hilos, usar tal caché como "almacenamiento" es en vano. –

+0

@Richard: De acuerdo.El especificador volátil nunca debe usarse como un medio para lograr la sincronización entre múltiples hilos. – Ankur

12

¡Su pregunta es técnicamente conocida como "una lata de gusanos"! Para c/C++ (No puedo comentar en java)
Puede resumir bastante volátil como una directiva para el compilador que diga 'no optimice esto', pero hay muchas discusiones entre profesionales, en cuanto a si es
a) At all useful for kernel level code < -Edit clarificado basa en la retroalimentación
b) Even implemented correctly by most compilers.

Además, no siempre utilizarlo para la programación multi-hilo y here's a very good explanation as to why

= Editar = Curiosamente, para lo que vale Dennis Ritchie estaba en contra de su inclusión (así como const) detalles here

+1

Debe tenerse en cuenta que el documento "En todo lo útil" se vincula al papel del kernel de Linux. Ese documento habla sobre la volatilidad utilizada en el kernel de Linux. En la parte inferior, todavía dan buenos usos de volátiles, que no se refieren a múltiples hilos. Volatile tiene sentido y es bueno allí (si el compilador trata los volátiles correctamente), como en un bucle ocupado donde la variable se actualiza en un manejador de interrupciones de la misma CPU. El compilador simplemente no puede saber si no debería optimizar una lectura. Su punto lo hace sonar como "volátil" es una porquería completa (aunque sé que no tiene la intención de hacerlo) :) –

+0

@litb Yep fair point. Haré ese punto más claro. No diría que fue una mierda total, solo pensé que señalaría que no es tan claro – zebrabox

+0

Exactamente lo que iba a decir. Una aclaración es que la optimización usualmente almacenaba el valor en un registro, reutilizándolo desde allí. Volatile fuerza al código a volver a leer el valor de la memoria en cada lectura y no a confiar en un valor en caché en el registro. Ahora los compiladores hacen muchas optimizaciones incluidas las sentencias de reescritura y su orden, por lo que simplemente releer un valor de la memoria no es suficiente si confías en el orden de actualización en otros subprocesos, para lidiar con esto se requieren barreras de memoria. – iain

4

Encontré este artículo DDJ de Herb Sutter muy interesante, especialmente sobre cómo se trata el volátil en C++, Java y C# .NET.

Dr.Dobbs volatile vs. volatile

+0

Gracias ovanes. Buena persona – Ankur

0

Ha sido un tiempo desde que he hecho en C++ y realmente no recuerdo la definición de volatine en ese idioma. Pero la especificación del lenguaje Java especifica que el propósito de la volatilidad es facilitar el acceso de múltiples subprocesos a una variable.Cita: "Un campo puede declararse volátil, en cuyo caso el modelo de memoria Java (§17) asegura que todos los hilos vean un valor constante para la variable". Continúan diciendo que se garantiza que las referencias a valores volátiles se satisfacen en el orden en que se especifican en el código, es decir, si declara que i y j son volátiles y luego escribe "++ i; ++ j", entonces yo de hecho, siempre se incrementará antes de j.

La única vez que recuerdo haber usado un volátil en Java fue cuando tuve un hilo posiblemente configurando un indicador de cancelación y otro hilo repitiendo una operación grande y cada vez que pasaba por el ciclo comprobando el indicador de cancelación. Esto de hecho funcionó como esperaba.

Estoy de acuerdo en que "volátil" tiene una utilidad muy limitada. La mayoría de multi-threading requiere "sincronizado" en algún punto. Pero "limitado" y "ninguno" no son lo mismo. La función del coseno también tiene una utilidad muy limitada en la mayoría de las aplicaciones comerciales. Pero cuando lo necesitas, wow, eso te ahorra muchos problemas.

1

La palabra clave volátil apareció hace mucho tiempo en C, y lo que hace básicamente es "desactivar" algunas optimizaciones del compilador que suponen que si una variable no se cambiaba explícitamente, no se cambiaba en absoluto. Su principal utilidad en esos días era declarar las variables que cambiarían los manejadores de interrupciones.Yo, por ejemplo, lo usé una vez (finales de los 80) para una variable global que contiene la posición del cursor del mouse. La posición fue modificada por una interrupción, y sin volátil el programa principal algunas veces no detectaría sus cambios porque el compilador optimizó el acceso variable, pensando que no era necesario.

Actualmente estos usos son, en general, obsoletos (a menos que escriba código OS de bajo nivel) pero todavía hay algunas situaciones raras en las que la volatilidad es útil (muy raro, por ejemplo, probablemente no use durante los últimos 7 años).

Pero para programación multiproceso no se recomienda. El problema es que no protegerá el acceso simultáneo entre subprocesos, solo eliminará las optimizaciones que evitarían su "actualización" en el mismo subproceso. No fue diseñado para su uso en entornos multiproceso. Si estás en Java, usa sincronizado. Si estás en C++, utiliza alguna biblioteca de sincronización, como pthreads o Boost.Threads (o, mejor aún, usa las nuevas librerías de subprocesos de C++ 0X, si puedes).

2

las variables volátiles son útiles en Java (por lo menos desde Java 5.0 donde su behaviour changed), como dice Brian Goetz en su libro "Java concurrencia en la práctica" (JCIP) - el libro esencial sobre el tema (pg 37):

para asegurar que las actualizaciones de una variable se propagan de manera predecible a otros hilos

sincronización explícita también puede lograrlo, pero a menudo no siempre quieren bloquear un valor. bloqueo doble registrado es el ejemplo clásico de esto (copiado de Wikipedia):

// Works with acquire/release semantics for volatile 
// Broken under Java 1.4 and earlier semantics for volatile 
class Foo { 
    private volatile Helper helper = null; 
    public Helper getHelper() { 
     if (helper == null) { 
      synchronized(this) { 
       if (null == helper) 
        helper = new Helper(); 
      } 
     } 
     return helper; 
    } 

    // other functions and members... 
} 

esto no funcionaría si el ayudante no era volátil.

Las variables volátiles también se pueden usar para implementar estructuras de datos simultáneas sin bloqueo, como java.util.concurrent.ConcurrentHashMap (que admite actualizaciones concurrentes y acceso sin bloqueo; consulte el código fuente de JDK para su uso de volátiles).

JCIP tiene una agradable discusión sobre el bloqueo comprobado, las variables volátiles y la concurrencia de Java en general. "Effective Java", 2nd Edition, de Joshua Bloch también vale la pena leerlo.

También tenga en cuenta que las variables atómicas son compatibles con Java en el paquete java.util.concurrent.atomic. Esto permite que los cambios en los valores se hagan visibles a través de subprocesos/procesadores de forma similar a las variables volátiles, pero también permite realizar operaciones de "Comparar y establecer", lo que significa que algunos tipos adicionales de operaciones concurrentes se pueden realizar sin bloqueo.