在 Linux 中的不同线程之间缓冲 `printf` 输出

Buffering `printf` outputs between different threads in Linux

这是我的代码:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>

pthread_t ntid;void
printids(const char *s) {
  printf("%s \n", s);
}

void *
thr_fn(void *arg)   {
  printids("new thread: ");
  return((void *)0);
}

int
main(void)  {
  pthread_create(&ntid, NULL, thr_fn, NULL);
  printids("main thread:");
}

我运行在 Red Hat Enterprise Linux 工作站版本 6.5 上安装它。
这是我的编译命令

gcc -ansi -g -std=c99 -Wall -DLINUX -D_GNU_SOURCE threadid.c -o threadid -pthread -lrt -lbsd

这是输出:

main thread:
new thread:
new thread:

为什么"new thread"被打印了两次? 我怀疑这可能与 Linux 中的缓冲机制有关。但是在我在每个函数的末尾添加 fflush(stdout)fsync(1) 之后。输出结果几乎一样。

如果你运行程序多次。输出不同:

main thread:
new thread:

main thread:
new thread:
new thread:

main thread:

大多数 libc 库都会像您提到的那样缓冲输出。在程序结束时(当主线程退出时),它们刷新所有缓冲区并退出。

您的新线程有可能刷新了输出,但在更新缓冲区状态之前,主程序退出并且清理代码再次刷新了同一个缓冲区。由于这些缓冲区是线程本地的,我确信它们不会有并发机制。但是由于这种罕见的情况,它可能会搞砸。

你可以试试

err = pthread_create(&ntid, NULL, thr_fn, NULL);
printids("main thread:");
pthread_join(ntid, NULL);

main函数结束,查看问题是否解决

这将导致您的主函数等待新线程完成(包括它执行的刷新操作)。

双重输出 在基于 glibc 的 linux 系统上是可能的,因为 glibc 中的一个讨厌的错误:如果 FILE 锁已经在time exit 尝试刷新,锁被简单地忽略并且缓冲区访问在没有同步的情况下执行。如果你能可靠地重现它,这将是一个很好的测试用例,可以向 glibc 报告以迫使他们修复它。