多线程 printf 与 write(2) 缓冲

Multithreaded printf vs write(2) buffering

在 Solaris 11.3 下考虑以下代码 运行:

void *run(void *args) {
  int i;
  for (i = 0; i < 100; i++) {
    printf("Line #%d printed by child\n", i + 1);
  }
}

int main() {
  pthread_t tid;
  int ret = pthread_create(&tid, NULL, run, NULL);
  int i;
  for (i = 0; i < 100; i++) {
    printf("Line #%d printed by parent\n", i + 1);
  }
  pthread_exit(NULL);
}

在 运行 之后,父线程总是在新创建的线程之前打印出它的所有行。有些人可能会说 pthread_create 太慢了,以至于其他线程甚至无法在主线程 returns 之前开始其工作。但是,将 printf 换成 write(2) 会产生 线程偶尔轮流打印行的预期输出。

如何解释这种行为?

缓冲当然与它无关,因为默认情况下终端输出是行缓冲的; writeprintf.

都应该是这样

即使函数使用某种阻塞技术来提供线程安全,究竟什么可以防止输出混乱?

完全是因为速度。如果你在 pthread_create 和循环之间调用 usleep,并稍微调整值,你可以让它混合一些行。

请注意,由于 stdio 锁定,一旦一个线程未能获得 stdout 上的锁一次或两次,它可能会休眠几毫秒(这将允许另一个线程完成其循环), 所以你不会看到很多混合。如果你想要更多的混合,你也需要在循环中放一个 usleep

在我的机器上,父循环之前的 usleep(50) 和两个循环中的 usleep(1) 将导致几乎交替的行。