2

假设我有两个线程打印一些东西(相对较长)到stderrstdout,这两个流的函数是线程安全的,因为它们永远不会“交错”字符?因此,例如,如果我有“Hello, World”,我将永远不会得到“HHellllo,, WorldWorld”或其他任何交错?这适用于 x86、GCC、Linux > 3.0。

4

2 回答 2

4

我看了一下 glibc,每次调用vfprintf都会在流上调用 POSIX flockfile( _IO_flockfile) 和funlockfile( _IO_funlockfile)。

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

不过,关于跨多个线程的多个调用的顺序,所有的赌注都没有了。

于 2012-10-20T14:37:03.710 回答
1

不会。即使在单线程程序中,由于不同的缓冲规则,您也可以进行交错。默认情况下,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);

或者通过使标准输出无缓冲。

于 2012-10-20T13:54:32.513 回答