【问题标题】:Who runs first in fork, with contradicting results谁在 fork 中先跑,结果自相矛盾
【发布时间】:2019-05-05 03:46:54
【问题描述】:

我有一个简单的测试:

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()kernel/fork.c)以将need_resched 标志设置为 1 结束,内核开发人员的评论说:“让子进程先运行。”

我猜这与 printf 写入的缓冲区有关。

另外,输入重​​定向 (&gt;) 是否会先将所有内容写入缓冲区,然后才复制到文件中?即便如此,为什么这会改变打印的顺序?

注意:我正在使用 Linux 内核 v2.4.14单核虚拟机上运行测试。

感谢您的宝贵时间。

【问题讨论】:

    标签: linux kernel fork scheduler


    【解决方案1】:

    当您重定向时,glibc 检测到 stdout 不是 tty 会打开输出缓冲以提高效率。因此,在进程退出之前不会写入缓冲区。您可以使用例如:

    int main() {
      printf("hello world\n");
      sleep(60);
    }
    

    当您以交互方式运行它时,它会打印“hello world”并等待。当你重定向到一个文件时,你会看到 60 秒内什么都没有写入:

    $ ./foo > file & tail -f file
    (no output for 60 seconds)
    

    由于您的父进程等待子进程,它必然总是最后退出,因此最后刷新其输出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多