2012-07-02 14 views
32

Al observar el estado de implementación Clang y g ++ C++ 11 noté algo extraño:
soportan C++ 11 atomics, pero no son compatibles con el modelo de memoria C++ 11.
Estaba bajo la impresión de que debe tener el modelo de memoria C++ 11 para usar átomos. Entonces, ¿cuál es exactamente la diferencia entre la compatibilidad con Atomics y el modelo de memoria?
¿La falta de compatibilidad con el modelo de memoria significa que los programas legales de C++ 11 que usan std::atomic<T> no son consistentes?¿Cómo pueden los compiladores de C++ son compatibles con C++ 11 atómica, pero no es compatible con C++ 11 modelo de memoria

referencias:
http://clang.llvm.org/cxx_status.html
http://gcc.gnu.org/gcc-4.7/cxx0x_status.html

+0

La atomicidad es una de las (tres?) Propiedades del modelo de memoria, junto con la visibilidad de la memoria y el orden de la memoria. La atomicidad no es un "sinónimo" de modelo de memoria. – mloskot

Respuesta

15

Uno de los problemas es la definición de "ubicación de la memoria", que permite (y obliga al compilador a admitir) el bloqueo de diferentes miembros de la estructura por diferentes bloqueos. Hay un discussion about a RL problem caused by this.

Básicamente el problema es que tener un struct define así:

struct x { 
    long a; 
    unsigned int b1; 
    unsigned int b2:1; 
}; 

el compilador es libre de implementar escrito a b2 sobrescribiendo b1 también (y, al parecer, a juzgar por el informe, que hace). Por lo tanto, los dos campos deben estar bloqueados como uno. Sin embargo, como consecuencia del modelo de memoria C++ 11, esto está prohibido (bueno, no está realmente prohibido, pero el compilador debe asegurarse de que las actualizaciones simultáneas a b1 y b2 no interfieran; podría hacerlo mediante bloqueo o CAS-ing cada una tal actualización, bueno, la vida es difícil en algunas arquitecturas). Citando el informe:

he planteado el tema a nuestros chicos del CCG y me dijeron que: "C no no constituir dicha garantía, ni se puede bloquear de forma fiable los diferentes campos de la estructura con diferentes cerraduras si comparten regiones de memoria de tamaño de palabra naturalmente alineadas . El modelo de memoria C++ 11 garantizaría esto, pero eso no está implementado ni construye el kernel con un compilador C++ 11 ".

Niza información también se puede encontrar en el wiki.

+0

técnico, pero esta es una buena información: el motivo por el que mencionamos el modelo de memoria C11/C++ 11 es porque tenemos previsto admitir que, probablemente para GCC 4.8, cuando lo soliciten algunas opciones (por defecto al elegir esas normas ?, o cuando se solicita explícitamente).Esto va a incluso deshabilitar algunas optimizaciones que están bien para aplicaciones de subproceso único, pero no están bien en esos modelos de memoria, no están bien en OpenMP o para muchos otros programas roscados . P.ej. loop store motion si no se garantiza que la variable siempre se almacena en el ciclo: – NoSenseEtAl

+0

int x; void foo (int j) { int i; para (i = 0; i <100000; i ++) if (i> j) x = i; } no se puede realizar, porque de lo contrario se introduce un tmp = x; ... x = tmp; en un código que de otra manera no tocaría la variable, por lo que si alguna ... otra cadena modifica x, podría tener un valor inesperado. \t Jakub – NoSenseEtAl

+0

genial editar (el enlace es increíble, a menudo me pregunto dónde viven las personas que hacen cosas mágicas (compiladores)) y por qué son tan tímidas para compartir información. :) hecho es que la mayor parte del tiempo la información está allí, pero no es fácilmente googlable :) – NoSenseEtAl

0

No es tanto que no son compatibles con el modelo de memoria, pero que no lo hacen (aún) compatible con la API en la Norma para interactuar con la memoria modelo. Esa API incluye una cantidad de mutexes.

Sin embargo, tanto Clang como GCC han sido lo más conscientes posible de los subprocesos sin un estándar formal durante algún tiempo. No tiene que preocuparse por las optimizaciones moviendo las cosas al lado equivocado de las operaciones atómicas.

+1

Esa respuesta es realmente insatisfactoria; la lista de características vinculadas en la pregunta * específicamente * habla sobre el modelo de memoria (y su propuesta), no sobre ninguna API, biblioteca, mutexes y otras cosas. Además, al menos gcc 4.7 * does * tiene los mutexes en la biblioteca. Hablar como "lo más consciente posible de los hilos sin un estándar formal" es solo una mierda; no significa nada. Thread aware no le dice nada sobre lo que hace el compilador y sin duda hay algo más que "mover las cosas al lado equivocado de las operaciones atómicas". – jpalecek

+1

@jpalecek, aunque estoy de acuerdo en que la respuesta no es tan buena que no hay necesidad de decir bs. :) Y sí mutexes están en g ++ de 4.6 al menos, aunque si recuerdo correctamente atomic_thread_fence wasnt. :) No puedo verificar ahora, (estoy en el cajero VS). – NoSenseEtAl

+0

@NoSenseEtAl: atomic_thread_fence está en gcc-4.7. Usé el término BS para referirme a frases de marketing vagas, como "soporte nativo para ...", que parecen ser importantes, pero después de pensar un poco, no significan nada. – jpalecek

11

Supongo que el "Modelo de falta de memoria" en estos casos solo significa que los optimizadores se escribieron antes de que se publicara el modelo de memoria C++ 11, y podrían realizar ahora optimizaciones no válidas. Es muy difícil y lleva mucho tiempo validar las optimizaciones en comparación con el modelo de memoria, por lo que no es una gran sorpresa que los equipos clang/gcc aún no hayan terminado.

¿La falta de compatibilidad con el modelo de memoria significa que los programas legales de C++ 11 que usan std :: atomic arent seq son consistentes?

Sí, es una posibilidad. Es incluso peor: el compilador podría introducir carreras de datos en (de acuerdo con el estándar C++ 11) los programas libres de raza, p. introduciendo escrituras especulativas.

Por ejemplo, varios compiladores de C++ que se utilizan para realizar esta optimización:

for (p = q; p = p -> next; ++p) { 
    if (p -> data > 0) ++count; 
} 

se pudo obtener optimizado en:

register int r1 = count; 
for (p = q; p = p -> next; ++p) { 
    if (p -> data > 0) ++r1; 
} 
count = r1; 

Si todo p->data no son negativos, el código fuente original no escribieron a count, pero el código optimizado sí lo hace. Esto puede introducir una carrera de datos en un programa sin carreras, por lo que la especificación C++ 11 no permite dichas optimizaciones. Los compiladores existentes ahora deben verificar (y ajustar si es necesario) todas las optimizaciones.

Ver Concurrency memory model compiler consequences para más detalles.

+0

¿sabes qué es gracioso? MS dice para VC++ 11: Modelo de memoria: N2429 hizo que Core Language reconozca la existencia de multihilo, pero parece que no hay nada que hacer para la implementación del compilador (al menos, uno que ya soportaba multihilo). Entonces es N/A en la mesa. – NoSenseEtAl

+0

@NoSenseEtAl: Es solo una parte muy específica de todo el modelo de memoria. La misma tabla también tiene "Ordenación de dependencia de datos" (N2664) que requirió trabajo. Por lo general, también lo contamos como parte del modelo de memoria C++ 11. – MSalters

+0

Ok ... entonces son flojos. Es lo que pensaba. –