对`fprintf(stdout,...)`和`fprintf(stderr,...)`的调用是否保证与多个线程不交错?

时间:2012-10-20 13:34:10

标签: c linux multithreading concurrency multicore

假设我有两个线程可以将某些内容(相对较长)打印到stderrstdout,这两个流的功能是线程安全的,因为它们永远不会#34;交织"字符?所以,例如,如果我有"你好,世界",我永远不会得到" HHellllo,WorldWorld"或者其他任何交错?这适用于x86,GCC,Linux> 3.0。

2 个答案:

答案 0 :(得分:4)

我看了一下glibc,每次拨打vfprintf都会调用POSIX flockfile_IO_flockfile)和funlockfile_IO_funlockfile)流。

因此,调用中的字符不会与来自另一个线程的调用中的字符交错,因为只有一个线程可以锁定stdoutstderr

关于跨越各个线程的多个调用的排序,所有的赌注都是关闭的。

答案 1 :(得分:1)

没有。即使在单线程程序中,由于不同的缓冲规则,您也可以进行交错。默认情况下,stdout是行缓冲的,而stderr是无缓冲的。您可以通过以下方式使它们无缓冲:

   setvbuf(stdout, NULL, _IONBF, 0)

另见stdout thread-safe in C on Linux?,特别是R.'s回答。还有Jonathan Leffler的comment

编辑:默认情况下,stdout在每行末尾或缓冲区已满时为fflush。后者可能发生在一条线的中间。然后,如果stdout和stderr都具有相同的底层文件描述符,则输出fprintf(stderr,...可以插入到行的中间。

但情况会更糟。通常,您希望将stderr和stdout重定向到文件或管道。系统上setbuf(3)的手册页注释:

  
    

如果流引用终端(正如stdout通常那样),则它是行缓冲的。默认情况下,标准错误流stderr始终是无缓冲的。

  

所以在这种情况下,stdout变为 block -buffered,实际上似乎几乎每个输出到stderr都与stdout的输出交错。这可以通过添加来缓解:

   setlinebuf(stdout);

或者使stdout无缓冲。