Esta es una gran pregunta.
Primero, C ++ 98 / C ++ 03 no tiene el concepto de "hilo". Entonces, en ese mundo, la pregunta no tiene sentido.
¿Qué pasa con C ++ 0x? Vea la respuesta de Martinho (que admito que me sorprendió).
¿Qué hay de las implementaciones específicas anteriores a C ++ 0x? Bueno, por ejemplo, aquí está el código fuente basic_streambuf<...>:sputc
de GCC 4.5.2 (encabezado "streambuf"):
int_type
sputc(char_type __c)
{
int_type __ret;
if (__builtin_expect(this->pptr() < this->epptr(), true)) {
*this->pptr() = __c;
this->pbump(1);
__ret = traits_type::to_int_type(__c);
}
else
__ret = this->overflow(traits_type::to_int_type(__c));
return __ret;
}
Claramente, esto no realiza ningún bloqueo. Y tampoco lo hace xsputn
. Y este es definitivamente el tipo de streambuf que usa Cout.
Por lo que puedo decir, libstdc ++ no bloquea ninguna de las operaciones de transmisión. Y no esperaría ninguno, ya que sería lento.
Entonces, con esta implementación, obviamente es posible que la salida de dos subprocesos se corrompa entre sí ( no solo se intercalen).
¿Podría este código dañar la estructura de datos en sí? La respuesta depende de las posibles interacciones de estas funciones; por ejemplo, qué sucede si un hilo intenta vaciar el búfer mientras otro intenta llamar xsputn
o lo que sea. Puede depender de cómo el compilador y la CPU decidan reordenar las cargas y almacenes de memoria; se necesitaría un análisis cuidadoso para estar seguro. También depende de lo que haga su CPU si dos subprocesos intentan modificar la misma ubicación al mismo tiempo.
En otras palabras, incluso si funciona bien en su entorno actual, podría romperse cuando actualice su tiempo de ejecución, compilador o CPU.
Resumen ejecutivo: "No lo haría". Cree una clase de registro que realice un bloqueo adecuado o muévala a C ++ 0x.
Como alternativa débil, puede configurar cout como sin búfer. Es probable (aunque no garantizado) que omita toda la lógica relacionada con el búfer y llame write
directamente. Aunque eso podría ser prohibitivamente lento.
printf
brilla, ya que la salida completa se escribe destdout
una vez; cuando el uso destd::cout
cada eslabón de la cadena de expresión se enviaría por separado astdout
; entre ellos puede haber algún otro hilo de escriturastdout
debido al cual el orden de la salida final se estropea.