Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are both calls to `fprintf(stdout, ...)` and `fprintf(stderr, ...)` guaranteed to non-interleave with multiple threads?

Say I have two threads that print something (relatively long) either to stderr or stdout, is the function to both these streams thread-safe in the sense that they will never "interleave" characters? So, for example, if I have "Hello, World", I will never get "HHellllo,, WorldWorld" Or whatever other interleaving? This is for x86, GCC, Linux > 3.0.

like image 948
Dervin Thunk Avatar asked Sep 20 '25 19:09

Dervin Thunk


2 Answers

I took a look at glibc, and each call to vfprintf will call the POSIX flockfile (_IO_flockfile) and funlockfile (_IO_funlockfile) on the stream.

So, the characters within a call won't get interleaved with characters from a call from another thread as only one thread can hold the lock on stdout or stderr.

All bets are off as to the ordering of multiple calls across the various threads though.

like image 183
Drew MacInnis Avatar answered Sep 22 '25 09:09

Drew MacInnis


No. Even in a single-threaded program you can get interleaving because of different buffering rules. By default, stdout is line-buffered while stderr is unbuffered. You can make them both unbuffered via:

   setvbuf(stdout, NULL, _IONBF, 0)

See also stdout thread-safe in C on Linux?, particularly R.'s answer. And also Jonathan Leffler's comment.

Edit: By default, stdout will be fflush'd at the end of each line or when the buffer is full. The latter could occur in the middle of a line. Then, if stdout and stderr both have the same underlying file descriptor, the output fprintf(stderr,... could be inserted into the middle of a line.

But it can be worse. Often you wish to redirect both stderr and stdout to a file or pipe. The man page for setbuf(3) on my system notes:

If a stream refers to a terminal (as stdout normally does) it is line buffered. The standard error stream stderr is always unbuffered by default.

So in this case, stdout becomes block-buffered, and in practice it seems that almost every output to stderr is interleaved with that of stdout. This can be alleviated by addding:

   setlinebuf(stdout);

Or by making stdout unbuffered.

like image 41
Joseph Quinsey Avatar answered Sep 22 '25 10:09

Joseph Quinsey