5

I am new to Boost threading and I am stuck with how output is performed from multiple threads. I have a simple boost::thread counting down from 9 to 1; the main thread waits and then prints "LiftOff..!!"

#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;
}

The problem is that I have to use an explicit "cout.flush()" statement in my thread to display the output. If I don't use flush(), I only get "LiftOff!!" as the output.

Could someone please advise why I need to use flush() explicitly?

Rajat
  • 467
  • 1
  • 5
  • 15
  • 1
    Behaves the same way for me with or without `flush()` (linux 3.0.6, gcc 4.5.3, boost 1.46). – CodeClown42 May 28 '12 at 12:22
  • FWIW, I tested your program on Win7x64 (MSVC10), and it prints out the numbers without flush(). Om what platform do you test it? – Igor R. May 28 '12 at 12:23
  • @KonradRudolph: "race conditions" will not create two separate stdout buffers, which is the only conceivable explanation for why the `endl` in main does not flush after waiting on a joined thread. (not to mention: there are no "race conditions" here at all, there are only two threads and one waits on the other.) – CodeClown42 May 28 '12 at 13:02
  • @goldilocks Ah, I overlooked the `join`. I was just assuming that the text *was* printed, only not in the correct order – but again, that’s obsolete since I overlooked the `join`. – Konrad Rudolph May 28 '12 at 13:05
  • I am using cygwin under windows 7(64 bit), g++ 4.5.3, boost 1.48 – Rajat May 28 '12 at 13:17
  • it shouldn't be buffering at all unless `std::ios_base::sync_with_stdio(false)` is set. – 111111 May 28 '12 at 13:17
  • also if you are trying to make a callable interface then the operator() should pure virtual. Although making an interface to do that isn't necessary. – 111111 May 28 '12 at 13:18

4 Answers4

5

This isn't specifically thread related as cout will buffer usually on a per thread basis and only output when the implementation decides to - so in the thread the output will only appear on a implementation specific basic - by calling flush you are forcing the buffers to be flushed.

This will vary across implementations - usually though it's after a certain amount of characters or when a new line is sent.

I've found that multiple threads writing too the same stream or file is mostly OK - providing that the output is performed as atomically as possible. It's not something that I'd recommend in a production environment though as it is too unpredictable.

Richard Harrison
  • 19,247
  • 4
  • 40
  • 67
3

This behaviour seems to depend on OS specific implementation of the cout stream. I guess that write operations on cout are buffered to some thread specific memory intermediatly in your case, and the flush() operation forces them being printed on the console. I guess this, since endl includes calling the flush() operation and the endl in your main function doesn't see your changes even after the thread has been joined.

BTW it would be a good idea to synchronize outputs to an ostream shared between threads anyway, otherwise you might see them intermigled. We do so for our logging classes which use a background thread to write the logging messages to the associated ostream.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • I'd be surprised to learn that implementing more than one stdout buffer per process is permissible by the standard, etc. BUT this does seem like the only possible explanation. Of course, only the OP seems to have observed this anyway o_O – CodeClown42 May 28 '12 at 13:06
  • @goldilocks: Yes agreed, the described behavior surprises me as well! But this can be OS specific even beyond the cout/stdout buffer implementation, doesn't it? Would be interesting to know which OS is used by the OP ... – πάντα ῥεῖ May 28 '12 at 13:15
  • Thanks makulik. your reasoning sounds good but its really wierd if cout has a different stream buffer per thread – Rajat May 28 '12 at 13:22
  • @Rajat: Take a look on Richard Harrison's answer, this would confirm my guess. Even though this is new to me as well ... – πάντα ῥεῖ May 28 '12 at 13:38
0

Given the short length of your messages, there's no reason anything should appear without a flush. (Don't forget that std::endl is the equivalent of << '\n' << std::flush.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

I get the asked behaviour with and without flush (gcc 4.3.2 boost 1.47 Linux RH5)

I assume that your cygwin system chooses to implement several std::cout objects with associated std::streambuf. This I assume is implementation specific. Since flush or endl only forces its buffer to flush onto its OS controlled output sequence the cout object of your thread remains buffered.

Sharing a reference of an ostream between the threads should solve the problem.

Daniel
  • 53
  • 7