多线程 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)
会产生
线程偶尔轮流打印行的预期输出。
如何解释这种行为?
缓冲当然与它无关,因为默认情况下终端输出是行缓冲的; write
和 printf
.
都应该是这样
即使函数使用某种阻塞技术来提供线程安全,究竟什么可以防止输出混乱?
完全是因为速度。如果你在 pthread_create
和循环之间调用 usleep
,并稍微调整值,你可以让它混合一些行。
请注意,由于 stdio 锁定,一旦一个线程未能获得 stdout
上的锁一次或两次,它可能会休眠几毫秒(这将允许另一个线程完成其循环), 所以你不会看到很多混合。如果你想要更多的混合,你也需要在循环中放一个 usleep
。
在我的机器上,父循环之前的 usleep(50)
和两个循环中的 usleep(1)
将导致几乎交替的行。
在 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)
会产生
线程偶尔轮流打印行的预期输出。
如何解释这种行为?
缓冲当然与它无关,因为默认情况下终端输出是行缓冲的; write
和 printf
.
即使函数使用某种阻塞技术来提供线程安全,究竟什么可以防止输出混乱?
完全是因为速度。如果你在 pthread_create
和循环之间调用 usleep
,并稍微调整值,你可以让它混合一些行。
请注意,由于 stdio 锁定,一旦一个线程未能获得 stdout
上的锁一次或两次,它可能会休眠几毫秒(这将允许另一个线程完成其循环), 所以你不会看到很多混合。如果你想要更多的混合,你也需要在循环中放一个 usleep
。
在我的机器上,父循环之前的 usleep(50)
和两个循环中的 usleep(1)
将导致几乎交替的行。