【发布时间】:2017-01-18 19:21:16
【问题描述】:
考虑以下在 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 太慢了,以至于其他线程甚至无法在主线程返回之前开始其工作。但是,将printf 换成write(2) 会产生
线程偶尔轮流打印它们的行的预期输出。
如何解释这种行为?
缓冲当然与它无关,因为终端输出默认是行缓冲的; write 和 printf 都应该是这样。
即使函数使用某种阻塞技术来提供线程安全,究竟是什么可以防止输出加扰?
【问题讨论】:
-
它是一个缓冲问题。您将
write(2)与fwrite(3)混淆了。write(2)是一个低级函数,没有缓冲。fwrite(3)是一个stdio函数,默认情况下是缓冲的。你会得到这种效果,因为stdout在后台线程中被块缓冲,而它在父线程中保持行缓冲。将setbuf(stdout, NULL)添加到两个线程并进行比较。 -
另一个线程的输出仍然是到终端,所以不应该像往常一样进行行缓冲吗?
-
“行缓冲”是
stdio的一个方面,而不是“终端”。write(2)不使用stdio,因此没有缓冲。 -
@SatoKatsura:这不是缓冲问题,因为两个线程都在写入同一个缓冲区。对
printf的每次调用都将获取stdout上的锁,然后写入该行(如果行缓冲将刷新,但如果没有则不会),然后释放锁
标签: solaris c io printf multithreading