2012-05-28 10 views
5

Sono nuovo di Boost per il threading e sono bloccato con il modo in cui l'output viene eseguito da più thread. Ho un semplice boost :: thread count down down da 9 a 1; il thread principale attende e quindi stampa "LiftOff .. !!"Filettatura BOOST: comportamento 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; 
} 

Il problema è che devo usare un "cout.flush()" esplicita dichiarazione nel mio thread per visualizzare l'output. Se non uso flush(), ottengo solo "LiftOff !!" come l'output.

Qualcuno potrebbe consigliare perché ho bisogno di usare flush() esplicitamente?

+1

Si comporta allo stesso modo per me con o senza 'flush()' (linux 3.0.6, gcc 4.5.3, boost 1.46). – delicateLatticeworkFever

+0

FWIW, ho testato il tuo programma su Win7x64 (MSVC10), e stampa i numeri senza flush(). Om quale piattaforma testate? –

+0

@KonradRudolph: "race condition" non creerà due buffer stdout separati, che è l'unica spiegazione plausibile per cui il file 'endl' in main non si svuota dopo aver atteso un thread congiunto. (per non parlare: non ci sono "condizioni di gara" qui, ci sono solo due thread e uno attende dall'altro.) – delicateLatticeworkFever

risposta

5

Questo non è specificamente legato Filettatura come cout per bufferizzare solito su una base per filo e emesso solo quando l'implementazione decide di - così nel filo all'uscita apparirà solo su una base di implementazione specifica - chiamando flush si sta costringendo i buffer a essere svuotati.

Questo può variare tra le implementazioni, di solito dopo un certo numero di caratteri o quando viene inviata una nuova riga.

Ho riscontrato che più thread che scrivono lo stesso flusso o file è per lo più OK, a condizione che l'output venga eseguito quanto più atomicamente possibile. Non è qualcosa che consiglierei in un ambiente di produzione perché è troppo imprevedibile.

3

Questo comportamento sembra dipendere dall'implementazione specifica del sistema operativo del flusso cout. Immagino che le operazioni di scrittura su cout vengano temporaneamente memorizzate nel buffer su una memoria specifica del thread e l'operazione flush() le impone di essere stampate sulla console. Immagino questo, dato che endl include la chiamata all'operazione flush() e l'endl nella tua funzione principale non vede le tue modifiche anche dopo che il thread è stato aggiunto.

BTW sarebbe una buona idea sincronizzare le uscite su un ostream condiviso tra i thread in ogni caso, altrimenti potresti vederli in modo intermittente. Lo facciamo per le nostre classi di registrazione che utilizzano un thread in background per scrivere i messaggi di registrazione sull'ostream associato.

+0

Sarei sorpreso di apprendere che l'implementazione di più di un buffer stdout per processo è consentita dallo standard, ecc. MA questa sembra l'unica spiegazione possibile. Naturalmente, solo l'OP sembra averlo osservato comunque o_O – delicateLatticeworkFever

+0

@goldilocks: Sì d'accordo, il comportamento descritto mi sorprende pure! Ma questo può essere specifico del sistema operativo anche oltre l'implementazione del buffer cout/stdout, vero? Sarebbe interessante sapere quale sistema operativo è utilizzato dall'OP ... –

+0

Grazie a makulik. il tuo ragionamento suona bene ma è davvero strano se cout ha un buffer di flusso diverso per thread – Rajat

0

Dato il breve tempo dei tuoi messaggi, non c'è motivo per cui qualsiasi cosa dovrebbe apparire senza un flush. (Non dimenticare che std::endl è l'equivalente di << '\n' << std::flush.)

0

ottengo il comportamento richiesto con e senza filo (gcc 4.3.2 boost 1.47 Linux RH5)

Presumo che il sistema Cygwin sceglie di implementare diversi std::cout oggetti con associata std::streambuf. Questo presumo è l'implementazione specifica. Poiché flush o endl forza solo il suo buffer per eseguire il flushing sulla sequenza di output controllata dal sistema operativo, l'oggetto cout del thread rimane bufferizzato.

La condivisione di un riferimento di uno ostream tra i thread dovrebbe risolvere il problema.