No hay subprocesos en C++ estándar y Threads cannot be implemented as a library.
Por lo tanto, la norma no tiene nada que decir sobre el comportamiento de los programas que usan subprocesos. Debe buscar las garantías adicionales proporcionadas por su implementación de subprocesamiento.
Dicho esto, en las implementaciones de roscado que he usado:
(1) sí, se puede asumir que los valores irrelevantes no se escriben en las variables. De lo contrario, el modelo de la memoria completa se va por la ventana. Pero tenga cuidado de que cuando diga "otro hilo" nunca establezca b
en falso, eso quiere decir en cualquier lugar, siempre. Si lo hace, esa escritura podría ser reordenada para que ocurra durante su ciclo.
(2) no, el compilador puede reordenar las asignaciones a b1 y b2, por lo que es posible que b1 termine verdadero y b2 falso. En un caso tan simple, no sé por qué reordenaría, pero en casos más complejos podría haber muy buenas razones.
[Editar: Vaya, cuando llegué a responder (2) Había olvidado que b era volátil. Las lecturas de una variable volátil no se volverán a ordenar, lo siento, por lo que sí en una implementación de subprocesamiento típica (si existe tal cosa), puede suponer que no terminará con b1 verdadero y b2 falso.]
(3) igual que 1.volatile
en general no tiene nada que ver con enhebrar en absoluto. Sin embargo, es bastante emocionante en algunas implementaciones (Windows), y podría implicar barreras de memoria.
(4) en una arquitectura donde las escrituras se int
sí atómicas, aunque volatile
no tiene nada que ver con ello. Consulte también ...
(5) revise los documentos con cuidado. Probablemente sí, y nuevamente volátil es irrelevante, porque en casi todas las arquitecturas int
escribe son atómicas. Pero si int
escribe no es atómico, entonces no (y no para la pregunta anterior), incluso si es volátil, en principio podría obtener un valor diferente. Sin embargo, dados esos valores 7 y 8, estamos hablando de una arquitectura bastante extraña para que el byte que contiene los bits relevantes se escriba en dos etapas, pero con valores diferentes, podría obtener una escritura parcial más plausible.
Para un ejemplo más plausible, supongamos que por alguna razón extraña tiene una int de 16 bits en una plataforma donde solo las escrituras de 8 bits son atómicas. Impar, pero legal, y dado que int
debe tener al menos 16 bits, puede ver cómo podría suceder. Supongamos, además, que su valor inicial se incrementa 255. A continuación, legalmente podría implementarse como:
- leer el valor antiguo
- incremento en un registro
- escribir el byte más significativo del resultado
- escribir la Byte menos significativo del resultado.
A de sólo lectura hilo que interrumpe el hilo de incrementación entre la tercera y cuarta etapas de que, podría ver el valor 511. Si las escrituras están en el otro orden, se podría ver 0.
Un el valor inconsistente se puede dejar de forma permanente si un hilo está escribiendo 255, otro hilo está escribiendo al mismo tiempo 256, y las escrituras se entrelazan. Imposible en muchas arquitecturas, pero para saber que esto no sucederá, necesitas saber al menos algo sobre la arquitectura. Nada en el estándar de C++ lo prohíbe, porque el estándar de C++ se refiere a la interrupción de la ejecución por una señal, pero de lo contrario no tiene el concepto de ejecución interrumpida por otra parte del programa, y ningún concepto de ejecución simultánea. Es por eso que los hilos no son solo otra biblioteca: agregar hilos fundamentalmente cambia el modelo de ejecución de C++. Requiere que la implementación haga las cosas de manera diferente, ya que eventualmente descubrirá si, por ejemplo, usa subprocesos bajo gcc y olvida especificar -pthreads
.
Lo mismo podría suceder en una plataforma en la que alineadosint
escrituras son atómicas, pero se les permite no alineados int
escribe y no atómica. Por ejemplo, IIRC en x86, las escrituras no alineadas int
no se garantizan atómicas si cruzan un límite de línea de caché. Los compiladores x86 no alinearán incorrectamente una variable declarada int
, por este motivo y otros. Pero si juegas juegos con estructura de embalaje probablemente puedas provocar un ejemplo.
Así que: prácticamente cualquier implementación le dará las garantías que necesita, pero podría hacerlo de una manera bastante complicada.
En general, he encontrado que no vale la pena tratar de confiar en las garantías específicas de la plataforma sobre el acceso a la memoria, que no entiendo completamente, para evitar mutexes. Use un mutex y, si es demasiado lento, use una estructura sin cerraduras de alta calidad (o implemente un diseño para uno) escrita por alguien que realmente conozca la arquitectura y el compilador.Probablemente sea correcto, y sujeto a corrección probablemente superará cualquier cosa que me invente.
¿Dónde se lee que "nada es atómica en C++"? Tenía la impresión de que cualquier lectura o escritura de un solo byte era atómica. Entonces, ¿podría verificar el valor de un bool, o asignarle un char ... o tal vez eran 32 bits que se garantizaba que eran atómicos? ¿Sería entonces 64 en una arquitectura de 64 bits? – mpen
@Mark: creo que quiso decir que el lenguaje C++ no garantiza la atomicidad de nada. Depende de la implementación específica (y la arquitectura de la CPU) lo que es o no es atómico. – jalf
@jalf: bueno ... está bien, quizás no sea propiedad de C++, pero sigue siendo una suposición razonablemente segura. Por lo tanto, al menos podemos responder la pregunta (1) con certeza. – mpen