2012-05-28 11 views
5

Soy nuevo en el enhebrado de Boost y estoy atascado con la forma en que la salida se realiza desde varios hilos. Tengo un impulso simple :: conteo de hilos de 9 a 1; el hilo principal espera y luego imprime "LiftOff .. !!"Enlazado de BOOST: comportamiento de cout

#include <iostream> 
#include <boost/thread.hpp> 
using namespace std; 

struct callable { 
    void operator()(); 
}; 

void callable::operator()() { 
    int i = 10; 
    while(--i > 0) { 
     cout << "#" << i << ", "; 
     boost::this_thread::yield(); 
    } 
    cout.flush(); 
} 

int main() { 
    callable x; 
    boost::thread myThread(x); 

    myThread.join(); 

    cout << "LiftOff..!!" << endl; 

    return 0; 
} 

El problema es que tengo que usar una "cout.flush()" explícita declaración en mi hilo para mostrar la salida. Si no uso flush(), solo obtengo "LiftOff !!" como la salida.

¿Podría alguien decirme por qué necesito usar flush() explícitamente?

+1

Se comporta de la misma manera para mí con o sin 'flush()' (linux 3.0.6, gcc 4.5.3, boost 1.46). – delicateLatticeworkFever

+0

FWIW, probé su programa en Win7x64 (MSVC10) e imprime los números sin vaciar(). ¿En qué plataforma lo pruebas? –

+0

@KonradRudolph: "condiciones de carrera" no creará dos almacenamientos intermedios separados, que es la única explicación concebible de por qué el 'endl' en main no funciona después de esperar en un hilo unido. (sin mencionar: aquí no hay "condiciones de carrera", solo hay dos hilos y uno espera por el otro). – delicateLatticeworkFever

Respuesta

5

Esto no está específicamente relacionado con hilos, ya que cout almacenará el buffer generalmente por subproceso y solo saldrá cuando la implementación lo decida, de modo que en el subproceso la salida solo aparecerá en un básico específico de la implementación: al invocar flush, está forzando el vaciado de los buffers.

Esto variará en las implementaciones, por lo general después de cierta cantidad de caracteres o cuando se envía una nueva línea.

He encontrado que varios hilos que escriben también la misma secuencia o archivo son en su mayoría correctos, siempre que la salida se realice de la manera más atómica posible. No es algo que recomendaría en un entorno de producción, ya que es demasiado impredecible.

3

Este comportamiento parece depender de la implementación específica del sistema operativo de la secuencia de comandos. Supongo que las operaciones de escritura en cout se almacenan temporalmente en una memoria específica de subprocesos en su caso, y la operación flush() obliga a que se impriman en la consola. Supongo que esto, ya que endl incluye llamar a la operación flush() y el endl en tu función principal no ve tus cambios incluso después de que se haya unido el hilo.

BTW sería una buena idea sincronizar las salidas a un ostream compartido entre subprocesos de todos modos, de lo contrario, es posible que los vea intercalados. Lo hacemos para nuestras clases de registro que usan un hilo de fondo para escribir los mensajes de registro en el ostream asociado.

+0

Me sorprendería saber que la implementación de más de un buffer estándar por proceso está permitido por el estándar, etc. PERO esta parece ser la única explicación posible. Por supuesto, solo el OP parece haber observado esto de todos modos o_O – delicateLatticeworkFever

+0

@goldilocks: Sí, de acuerdo, ¡el comportamiento descrito también me sorprende! Pero esto puede ser específico del sistema operativo incluso más allá de la implementación del búfer cout/stdout, ¿no? Sería interesante saber qué sistema operativo utiliza el OP ... –

+0

Gracias makulik. su razonamiento suena bien, pero es realmente extraño si cout tiene un buffer de flujo diferente por hilo – Rajat

0

Dada la brevedad de sus mensajes, no hay motivo por el que algo debería aparecer sin una descarga. (No olvide que std::endl es el equivalente a << '\n' << std::flush.)

0

me sale el comportamiento pedido con y sin rubor (gcc 4.3.2 boost 1.47 Linux RH5)

Asumo que su sistema cygwin elige implementar varios objetos con std::cout asociada std::streambuf. Esto supongo que es específico de la implementación. Dado que flush o endl solo fuerzan su buffer para enjuagar en su secuencia de salida controlada por el sistema operativo, el objeto de conversación de su hilo permanece almacenado.

Compartir una referencia de ostream entre los hilos debería resolver el problema.