假设我有两个线程打印一些东西(相对较长)到stderr
或stdout
,这两个流的函数是线程安全的,因为它们永远不会“交错”字符?因此,例如,如果我有“Hello, World”,我将永远不会得到“HHellllo,, WorldWorld”或其他任何交错?这适用于 x86、GCC、Linux > 3.0。
2 回答
我看了一下 glibc,每次调用vfprintf
都会在流上调用 POSIX flockfile
( _IO_flockfile
) 和funlockfile
( _IO_funlockfile
)。
因此,调用中的字符不会与来自另一个线程的调用中的字符交错,因为只有一个线程可以保持stdout
或锁定stderr
。
不过,关于跨多个线程的多个调用的顺序,所有的赌注都没有了。
不会。即使在单线程程序中,由于不同的缓冲规则,您也可以进行交错。默认情况下,stdout 是行缓冲的,而 stderr 是非缓冲的。您可以通过以下方式使它们都不受缓冲:
setvbuf(stdout, NULL, _IONBF, 0)
另请参阅Linux 上 C 中的 stdout 线程安全?,尤其是R. 的回答。还有 Jonathan Leffler 的评论。
编辑:默认情况下,stdout 将fflush
在每行末尾或缓冲区已满时显示。后者可能发生在一行的中间。然后,如果 stdout 和 stderr 都具有相同的底层文件描述符,则输出 fprintf(stderr,... 可以插入到一行的中间。
但情况可能更糟。通常您希望将 stderr 和 stdout 都重定向到文件或管道。我系统上的手册页setbuf(3)
说明:
如果流引用终端(如标准输出通常那样),则它是行缓冲的。默认情况下,标准错误流 stderr 始终是无缓冲的。
所以在这种情况下,stdout 变成了块缓冲,实际上似乎几乎每个到 stderr 的输出都与 stdout 的输出交错。这可以通过添加来缓解:
setlinebuf(stdout);
或者通过使标准输出无缓冲。