2012-05-28 14 views
5

Jestem nowy, aby zwiększyć wątki i utknąłem z tym, jak wyniki są wykonywane z wielu wątków. Mam prosty impuls: odliczanie wątków od 9 do 1; główny wątek czeka, a następnie drukuje "LiftOff .. !!"Nawlekanie wątków: zachowanie 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; 
} 

Problem polega na tym, że muszę użyć wyraźnej instrukcji "cout.flush()" w moim wątku, aby wyświetlić wynik. Jeśli nie użyję funkcji flush(), otrzymam tylko "LiftOff !!" jako wyjście.

Czy ktoś może doradzić, dlaczego muszę użyć flush() jawnie?

+1

Zachowuje się tak samo dla mnie z lub bez 'flush()' (Linux 3.0.6, gcc 4.5.3, doładowanie 1.46). – delicateLatticeworkFever

+0

FWIW, testowałem twój program na Win7x64 (MSVC10) i wypisuję liczby bez spłukiwania(). Jaką platformę testujesz? –

+0

@KonradRudolph: "warunki wyścigu" nie stworzą dwóch oddzielnych buforów standardowych, co jest jedynym możliwym do wyobrażenia wyjaśnieniem, dlaczego 'endl' w main nie spłukuje się po oczekiwaniu na połączony wątek. (nie wspominając już o tym, że w ogóle nie ma tutaj "warunków wyścigu", są tylko dwa wątki i jeden czeka po drugiej). – delicateLatticeworkFever

Odpowiedz

5

To nie jest specjalnie nici podobne jak cout buforuje zwykle w przeliczeniu na podstawie gwintu i tylko wyjście, gdy realizacja zdecyduje się - tak w wątku wyjścia pojawi się tylko na konkretnym poziomie implementacji - wywołując flush, zmuszasz do przepłukania buforów.

Może się to różnić w zależności od implementacji - zwykle po określonej liczbie znaków lub po wysłaniu nowej linii.

Odkryłem, że wiele wątków zapisujących zbyt ten sam strumień lub plik jest w większości sprawne - pod warunkiem, że dane wyjściowe są wykonywane możliwie jak najbardziej niepodzielnie. To nie jest coś, co polecam w środowisku produkcyjnym, ponieważ jest zbyt nieprzewidywalne.

3

To zachowanie wydaje się zależeć od implementacji strumienia cout dla konkretnego systemu operacyjnego. Domyślam się, że operacje zapisu na cout są buforowane do pewnej pamięci specyficznej dla wątku pośrednio w twoim przypadku, a operacja flush() zmusza je do drukowania na konsoli. Zgaduję, że to dlatego, że endl zawiera wywołanie operacji flush(), a endl w twojej głównej funkcji nie widzi twoich zmian nawet po przyłączeniu wątku.

BTW dobrym pomysłem byłoby zsynchronizowanie wyjść do ostream udostępnionego między wątkami, w przeciwnym razie możesz zobaczyć, jak się ze sobą mieszają. Robimy to dla naszych klas logowania, które używają wątku tła do zapisywania komunikatów logowania do powiązanego ostream.

+0

Byłbym zaskoczony, gdy dowiedziałem się, że zaimplementowanie więcej niż jednego standardowego bufora na proces jest dozwolone przez standard itp. ALE wydaje się to jedynym możliwym wyjaśnieniem. Oczywiście, tylko PO zdaje się to zaobserwować i tak o_O – delicateLatticeworkFever

+0

@goldilocks: Zgadzam się, opisane zachowanie również mnie zaskakuje! Ale może to być OS specyficzne nawet poza implementacją bufora cout/stdout, prawda? Byłoby interesujące dowiedzieć się, który system operacyjny jest używany przez OP ... –

+0

Dzięki makulik. twoje rozumowanie brzmi dobrze, ale jest naprawdę dziwne, jeśli cout ma inny bufor strumienia na wątek – Rajat

0

Biorąc pod uwagę krótki czas trwania Twoich wiadomości, nie ma powodu, aby cokolwiek mogło się wydawać bez koloru. (Nie należy zapominać, że std::endl jest odpowiednikiem << '\n' << std::flush.)

0

otrzymuję hasła zachowanie zi bez spłukiwania (gcc 4.3.2 boost 1.47 Linux RH5)

Zakładam, że system Cygwin zdecyduje się wdrożyć kilka std::cout obiektów z towarzyszącym std::streambuf. Zakładam, że jest to konkretna implementacja. Od flush lub endl tylko wymusza jego bufor, aby opróżnić się na jego sekwencję wyjściową sterowaną przez OS, obiekt cout wątku pozostaje zbuforowany.

Udostępnianie odwołania między ostream między wątkami powinno rozwiązać problem.