Is stdout thread safe in C on Linux?

Is writing to stdout using printf thread safe on Linux? How about using the lower level write command?

+32
c linux unix operating-system
Jan 22 '09 at 3:16
source share
5 answers

It is not specified by the C standard - it depends on your implementation of the C standard library. In fact, the C standard does not even mention threads at all, since some systems (for example, embedded systems) do not have multithreading.

In the GNU implementation ( glibc ), most of the top-level functions in stdio that deal with FILE* objects are thread safe. Those that usually do not have unlocked in their names (e.g. getc_unlocked(3) ). However, thread safety depends on the call level for each function: if you make several calls to printf(3) , for example, each of these calls is guaranteed to be output atomically, but other threads can print things between your calls before printf() . If you want the I / O call sequence to be output atomically, you can surround them with a pair of flockfile(3)/funlockfile(3) calls to block the FILE descriptor. Note that these functions are reentrant, so you can safely call printf() between them, and this will not lead to a deadlock, even the thought of printf() itself makes a call to flockfile() .

Low-level I / O calls, such as write(2) , should be thread safe, but I'm not 100% sure - write() makes a system call in the kernel to do I / O. How exactly this happens depends on which kernel you use. This can be a sysenter command or an int (interrupt) statement for older systems. Once inside the kernel, up to the kernel to make sure I / O is thread safe. In the test that I just did with Darwin's kernel version 8.11.1, write(2) seems thread safe.

+47
Jan 22 '09 at 5:07
source share

Whether you will call it “thread safe” depends on your definition of thread safety. POSIX requires stdio functions to use a lock, so your program will not crash, corrupt the state of a FILE object, etc. if you use printf from multiple threads at the same time. However, all stdio operations are formally specified in terms of fgetc and fputc , so a larger atomicity is guaranteed. That is, if threads 1 and 2 try to print "Hello\n" and "Goodbye\n" at the same time, there is no guarantee that the output will be either "Hello\nGoodbye\n" or "Goodbye\nHello\n" . It can also be "HGelolodboy\ne\n" . In practice, most implementations will acquire a single lock for the whole call at a higher level, because it is more efficient, but your program should not allow this. There may be angular cases when this is not done; for example, an implementation may completely eliminate blocking of unbuffered threads.

Edit: The above atomicity text is incorrect. POSIX guarantees that all stdio operations are atomic, but the guarantee is hidden in the documentation for flockfile : http://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html

All functions that reference objects (FILE *) must behave as if they used flockfile () and funlockfile () internally to obtain ownership of these objects (FILE *).

You can use the flockfile , ftrylockfile and funlockfile functions flockfile to ftrylockfile write larger than single-line ones.

+20
Jul 26 2018-10-29T00:
source share

They are both thread safe to the point that your application will not crash if multiple threads call them in the same file descriptor. However, without any lock at the application level, everything that is written can be interleaved.

+12
Jan 22 '09 at 3:20
source share

It is thread safe; printf should be reentrant and you won’t cause any weirdness or corruption in your program.

You cannot guarantee that your output from one thread will not start halfway through the output from another thread. If you care, you need to develop your own locked output code to prevent multiple access.

+4
Jan 22 '09 at 3:19
source share

C got a new standard since this question was asked (and the last answer).

C11 now supports multithreading and supports multithreaded thread behavior:

§7.21.2 Streams

¶7 Each thread has an associated lock that is used to prevent data races when multiple threads execute access to a thread and restrict the interleaving of thread operations performed by multiple threads. Only one thread can hold this lock at a time. A lock is reentrant: a single thread can hold a lock several times in a certain amount of time.

¶8 . All functions that read, write, position or request the position of the stream block the stream until it is accessed. They release the lock associated with the thread when access is complete.

So, an implementation with C11 threads should ensure that using printf is thread safe.

Whether atomicity is (as in the absence of interleaving 1 ), it was not so clear to me at first glance, because the standard spoke of restricting rotation, and not the prevention that it entrusted for data racing.

I tend to be sure. The standard speaks of restricting the rotation, since some interleaving is still allowed, which does not change the result; for example fwrite few bytes, fseek return a little more and fwrite to the original offset, so both fwrite will be inverse. An implementation can modify these 2 fwrite and merge them into one record.




1 : see push text in R .. answer for an example.

+3
Dec 13 '16 at 21:56
source share



All Articles