linux - 谁在 fork 中先跑,结果自相矛盾
问题描述
我有这个简单的测试:
int main() {
int res = fork();
if (res == 0) { // child
printf("Son running now, pid = %d\n", getpid());
}
else { // parent
printf("Parent running now, pid = %d\n", getpid());
wait(NULL);
}
return 0;
}
当我运行它一百次时,即运行这个命令,
for ((i=0;i<100;i++)); do echo ${i}:; ./test; done
我得到:
0:
Parent running now, pid = 1775
Son running now, pid = 1776
1:
Parent running now, pid = 1777
Son running now, pid = 1778
2:
Parent running now, pid = 1779
Son running now, pid = 1780
等等; 而当我第一次写入文件然后读取文件时,即运行此命令,
for ((i=0;i<100;i++)); do echo ${i}:; ./test; done > forout
cat forout
我把它翻了!那是,
0:
Son running now, pid = 1776
Parent running now, pid = 1775
1:
Son running now, pid = 1778
Parent running now, pid = 1777
2:
Son running now, pid = 1780
Parent running now, pid = 1779
我知道调度程序。就分叉后谁先跑而言,这个结果不意味着什么?分叉函数do_fork()
(at kernel/fork.c
) 以将need_resched
标志设置为 1 结束,内核开发人员的评论说“让子进程先运行”。
我猜这与 printf 写入的缓冲区有关。
另外,说输入重定向 ( >
) 首先将所有内容写入缓冲区,然后才复制到文件,这是真的吗?即便如此,为什么这会改变打印的顺序?
注意:我正在使用 Linux 内核v2.4.14的单核虚拟机上运行测试。
感谢您的时间。
解决方案
当您重定向时,glibc 检测到 stdout 不是 tty 打开输出缓冲以提高效率。因此,在进程退出之前不会写入缓冲区。您可以通过以下方式看到这一点:
int main() {
printf("hello world\n");
sleep(60);
}
当您以交互方式运行它时,它会打印“hello world”并等待。当您重定向到一个文件时,您会看到 60 秒内没有任何内容被写入:
$ ./foo > file & tail -f file
(no output for 60 seconds)
由于您的父进程等待子进程,它必然总是最后退出,因此最后刷新其输出。
推荐阅读
- python - 模块中的连续错误:TypeError:Artist() 不接受任何参数
- php - 为什么for循环后的mycode没有执行?
- geometry - 使用 S2 几何库在数据库上执行位置邻近搜索
- excel - vb.net 在等待进程时显示动画 Gif
- python - 退格字符不起作用 - 使用 python 在 cmd 上打印
- java - BottomNavigationView 图标/文本动画
- django - 如何在 django admin 中内联显示两个表?
- r - R:通过检查旧数据框的第一列值是否与第三个数据框的第一列值匹配,从旧数据框创建新数据框
- python - 在 tkinter Canvas 上绘制变量图像
- c# - 调用 API 时 Xamarin 应用程序出现问题