¿Son suficientes las funciones de bloqueo mutex sin volátiles?


Un compañero de trabajo y yo escribimos software para una variedad de plataformas que se ejecutan en x86, x64, Itanium, PowerPC y otras CPU de servidor de 10 años.

Acabamos de tener una discusión sobre si mutex funciona como pthread_mutex_lock() ... pthread_mutex_unlock () son suficientes por sí mismos, o si la variable protegida necesita ser volátil.

int foo::bar()
{
 //...
 //code which may or may not access _protected.
 pthread_mutex_lock(m);
 int ret = _protected;
 pthread_mutex_unlock(m);
 return ret;
}

Mi preocupación es el almacenamiento en caché. ¿Podría el compilador colocar una copia de _protected en la pila o en un registro, y usar ese valor obsoleto en la tarea? Si no, ¿qué impide que eso suceda? ¿Son vulnerables las variaciones de este patrón?

Supongo que el compilador no entiende realmente que pthread_mutex_lock() es una función especial, por lo que estamos protegidos por puntos de secuencia?

Muchas gracias.

Actualización: Muy bien, puedo ver una tendencia con respuestas que explican por qué volátil es malo. Respeto esas respuestas, pero los artículos sobre ese tema son fáciles de encontrar en línea. Lo que no puedo encontrar en línea, y el la razón por la que estoy haciendo esta pregunta, es cómo estoy protegido sin volátil. Si el código anterior es correcto, ¿cómo es invulnerable a los problemas de almacenamiento en caché?

Author: starblue, 2011-07-27

4 answers

Si el código anterior es correcto, ¿cómo es invulnerable al almacenamiento en caché problemas?

Hasta C++0x, no lo es. Y no se especifica en C. Por lo tanto, realmente depende del compilador. En general, si el compilador no garantiza que respetará las restricciones de orden en los accesos a la memoria para funciones u operaciones que involucran múltiples subprocesos, no podrá escribir código seguro multiproceso con ese compilador. Ver Hans J Boehm Hilos No pueden ser Implementado como una biblioteca .

En cuanto a las abstracciones que su compilador debería soportar para el código seguro de subprocesos, la entrada de wikipedia en Barreras de memoria es un buen punto de partida.

(En cuanto a por qué la gente sugirió volatile, algunos compiladores tratan volatile como una barrera de memoria para el compilador. Definitivamente no es estándar.)

 8
Author: MSN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-26 23:54:46

La respuesta más simple es volatile no es necesaria para multi-threading en absoluto.

La respuesta larga es que los puntos de secuencia como las secciones críticas dependen de la plataforma, al igual que cualquier solución de roscado que esté utilizando, por lo que la mayor parte de su seguridad de subprocesos también depende de la plataforma.

C++0x tiene un concepto de subprocesos y seguridad de subprocesos, pero el estándar actual no lo tiene y, por lo tanto, volatile a veces se identifica erróneamente como algo para evitar el reordenamiento de las operaciones y el acceso a la memoria para programación multi-threading cuando nunca fue previsto y no se puede utilizar de forma fiable de esa manera.

Lo único para lo que se debe usar volatile en C++ es permitir el acceso a dispositivos mapeados de memoria, permitir el uso de variables entre setjmp y longjmp, y permitir el uso de variables sig_atomic_t en manejadores de señales. La palabra clave en sí no hace una variable atómica.

Buenas noticias en C++0x tendremos la construcción STL std::atomic que se puede usar para garantizar operaciones atómicas y construcciones seguras de subprocesos para variables. Hasta que el compilador de su elección lo soporte, puede que tenga que recurrir a la biblioteca boost o extraer algún código ensamblador para crear sus propios objetos para proporcionar variables atómicas.

P.d. Una gran parte de la confusión es causada por Java y.NET en realidad la aplicación de semántica multihilo con la palabra clave volatile C++ sin embargo sigue el ejemplo con C donde este no es el caso.

 14
Author: AJG85,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-26 23:39:43

Su biblioteca de subprocesos debe incluir las barreras de CPU y compilador apropiadas en mutex lock and unlock. Para GCC, un clobber memory en una sentencia asm actúa como una barrera del compilador.

En realidad, hay dos cosas que protegen su código del almacenamiento en caché (del compilador):

  • Está llamando a una función externa no pura (pthread_mutex_*()), lo que significa que el compilador no sabe que esa función no modifica sus variables globales, por lo que tiene que recargarlas.
  • Como dije, pthread_mutex_*() incluye una barrera de compilador, por ejemplo: on glibc / x86 pthread_mutex_lock() termina llamando a la macro lll_lock(), que tiene un clobber memory, forzando al compilador a recargar variables.
 8
Author: ninjalj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-28 20:23:47

La palabra clave volatile es una sugerencia para el compilador de que la variable podría cambiar fuera de la lógica del programa, como un registro de hardware mapeado en memoria que podría cambiar como parte de una rutina de servicio de interrupción. Esto evita que el compilador asuma que un valor almacenado en caché siempre es correcto y normalmente forzaría una lectura de memoria para recuperar el valor. Este uso es anterior al enhebrado por un par de décadas más o menos. He visto que se utiliza con variables manipuladas por señales, así, pero no estoy seguro de que el uso era correcto.

Las variables guardadas por mutexes están garantizadas para ser correctas cuando son leídas o escritas por hilos diferentes. La API de subprocesos es necesaria para garantizar que dichas vistas de las variables sean coherentes. Este acceso es todo parte de la lógica de su programa y la palabra clave volátil es irrelevante aquí.

 3
Author: jbruni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-26 23:29:45