3

I am starting to learn threads in the C++11 standard and I was trying out a very basic program which creates 10 threads, joins them and then exits. In the thread function, I tried to print out the index of the for loop that I'm creating the threads in, like this:

std::vector<std::thread> threads;
for(int i = 0; i < 10; i++)
{
    threads.push_back(std::thread([i](){ printf("Thread #%d\n", i); }));
}

And this produces an output expected from a concurrent program, the threads execute out of order:

Thread #0
Thread #2
Thread #1
Thread #3
Thread #4
Thread #5
Thread #6
Thread #7
Thread #8
Thread #9

But when I try to do the same thing using std::cout and std::endl, I get this:

Thread #0
Thread #Thread #2
Thread #3
Thread #9
1
Thread #8
Thread #4
Thread #5
Thread #7
Thread #6

Why is this happening with std::cout but not with printf?

Mertcan Ekiz
  • 691
  • 1
  • 9
  • 22
  • Why would you expect the first output? – Yakk - Adam Nevraumont Nov 02 '14 at 19:47
  • If your application is running on Windows then `printf` seems to have a mutex restricting access to STDOUT. I've never found some documentation confirming this but that's what I've observed over the years... – Lukas Thomsen Nov 02 '14 at 19:50
  • @Yakk Well I would like it better if they were in order but it's my understanding that threads usually don't work that way, am I wrong? – Mertcan Ekiz Nov 02 '14 at 19:50
  • @LukasThomsen I am on Linux, using gcc 4.8.2 – Mertcan Ekiz Nov 02 '14 at 19:51
  • 7
    Your `std::cout` version uses multiple function calls. One call to print something can't possibly know you're going to make another call to print a newline after it and thus ensure nothing else is printed in between. – chris Nov 02 '14 at 19:53
  • @chris I see. So would the correct way to output in this case be to use `printf` ? – Mertcan Ekiz Nov 02 '14 at 20:09
  • 1
    @MertcanEkiz: Or use `sprintf` or `stringstream` to build a combined message, and write it to `cout` with a single call. – Ben Voigt Nov 02 '14 at 20:15
  • Also see [Is cout synchronized/thread-safe?](https://stackoverflow.com/q/6374264/608639) – jww May 27 '18 at 11:34

2 Answers2

6

You did not show your std::cout code.

threads.push_back(std::thread([i](){ printf("Thread #%d\n", i); }));

But if I assume you changed the code to:

threads.push_back(std::thread([i](){ std::cout << "Thread #" << i << std::endl; }));

There is considerable different in the two:

The printf version has only one call to the printing libraries.:

printf("Thread #%d\n", i);

The operator<< has three distinct calls to the printing libraries

operator<<(std::cout, "Thread #");
operator<<(std::cout, i);
operator<<(std::cout, std::endl);

// note for the pedantic the use of functions here is for illustration purposes.

Assuming the printing library has some sort of lock internally the printf version will give you a line for each thread. While the operator<< version may be preempted between calls.

I would not bet on any version even having an internal lock. The printing section is probably just short enough that observing an interrupt there has a small probability and thus you may not have observed it yet.

Try:

threads.push_back(std::thread([i]()
{  std::stringstream msg;
   msg << "Thread #" << i << "\n";
   std::cout << msg.rdbuf();
}));
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Your assumption was correct. I understand now, thanks for the clear answer – Mertcan Ekiz Nov 02 '14 at 20:27
  • Neithe `printf`, nor `cout` offer ANY guarantee that even a single call is threadsafe. In fact, I often see "mixed up" output from threads in my work - I made special efforts to ensure that the output is "a single call comes out together" when I implemented `printf` for OpenCL. It may well work fine for short strings, and "break" when you have long strings, for example (because there is a limited amount of space in some buffer). – Mats Petersson Nov 03 '14 at 00:14
  • The only thing guaranteed about the standard stream objects is that if it is synchronized with stdio then concurrent accesses to its formatted or unformatted I/O functions do not constitute a data race (i.e., is not undefined behavior); the printed characters can still interleave. – T.C. Nov 03 '14 at 07:06
0

As far as I know the preempted behaviour is not guaranteed Let me assume you end the line in std::cout with std::endl. std::endl does more then just adding '\n' it also flushes the internal buffer which from my experience is a protected action between threads. If you replace std::endl with '\n' it should also mix up output between threads. Further more if you write very long lines into your std::cout you may force a buffer overrun and a flush if std::cout and in that case output may also be mixed up.

Oncaphillis
  • 1,888
  • 13
  • 15
  • 1
    I think you misunderstood. `std::cout` and `std::endl` *does* mix the outputs, `printf` does not. – Mertcan Ekiz Nov 02 '14 at 20:04
  • 1
    @MertcanEkiz: Just because you have not observed it does not mean it will not happen. – Martin York Nov 02 '14 at 20:12
  • @LokiAstari Yes that's true. I've been wondering if it would at some point happen so I've run the application over and over again but the result didn't change – Mertcan Ekiz Nov 02 '14 at 20:13
  • The effect this answer describes would prevent intermingling of characters from `cout` and other output methods. It wouldn't prevent intermingling between multi-threaded uses of `cout`, which share the same buffer. And you can't change *that* without breaking valid code that, because of cross-thread synchronization, produces output interleaved in a controlled way. – Ben Voigt Nov 02 '14 at 20:14