【问题标题】:Which process runs first when a fork() is called调用 fork() 时哪个进程首先运行
【发布时间】:2013-08-18 22:50:55
【问题描述】:

这个程序是我写的

main()
{
    int pid;
    pid=fork();
    if(pid==0)
        printf("\nI am child\n");
    else
        printf("\nI am parent\n");

    return 0;
}

执行时谁的输出是

 ./a.out 

I am parent

I am child

当我使用 strace 程序运行时,输出是 [Last part]

arch_prctl(ARCH_SET_FS, 0x7fd1bbf52700) = 0
mprotect(0x7fd1bbd47000, 16384, PROT_READ) = 0
mprotect(0x7fd1bbf70000, 4096, PROT_READ) = 0
munmap(0x7fd1bbf54000, 103886)          = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fd1bbf529d0) = 5109

I am child
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
--- SIGCHLD (Child exited) @ 0 (0) ---
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd1bbf6d000
write(1, "\n", 1
)                       = 1
write(1, "I am parent\n", 12I am parent
)           = 12
exit_group(13)                          = ?

输出显示 parent 首先运行,但 strace 输出似乎显示 child 先运行,因为它首先打印。

规则是什么?

【问题讨论】:

标签: linux process linux-kernel fork


【解决方案1】:

没有规则。一旦进程准备好执行(即fork 系统调用返回),它就可以根据调度配置(优先级、选择的调度程序等)运行。根据进程添加到调度程序的方式,可以在从fork 返回后首先调度任一进程。 (而且,正如@nos 在评论中指出的那样,两个进程可以在多 CPU/多核系统上同时运行)。

此外,在使用printf 时,请记住,即使进程是按照固定规则安排的,输出刷新也可能以不同的顺序发生。这就是为什么 no-strace 和 strace 运行的输出不同的原因。

【讨论】:

  • 您甚至可能有 2 个处理器,因此它们可以同时运行。
  • strace 也可能会增加一些延迟并影响先运行的延迟。
【解决方案2】:

在大多数情况下是父进程

fork() 不是阻塞系统调用,所以除非父进程已经用完它的调度量,否则它将在分叉之后继续运行。子进程放在就绪列表中,将由下一个可用的cpu运行,但父进程会在系统调用返回时立即运行。

这是一个小程序产生的输出,该小程序分叉 10 个子进程,在 2 核笔记本电脑上运行:

PARENT child PARENT PARENT child PARENT PARENT child PARENT PARENT child PARENT PARENT child PARENT child child child child child
PARENT child PARENT child PARENT PARENT PARENT child PARENT PARENT child PARENT PARENT child PARENT child child child child child
PARENT child PARENT PARENT child PARENT PARENT child PARENT PARENT child PARENT PARENT child PARENT child child child child child
PARENT child PARENT PARENT child PARENT PARENT child PARENT PARENT child PARENT PARENT child PARENT child child child child child

main() {
    int i;
    for (i=0; i<10; i++) {
        if (fork()) {
            write(1, "PARENT ", 7);
        }
        else {
            write(1, "child ", 6);
            exit(0);
        }
    }
}

编辑:但是,写 is 是一个阻塞调用。更好的测试记录子进程 ​​pid,并且也有子进程。如果父进程之间没有子进程运行,它将分配连续的 pid。这是连续 20 个分叉的运行(换行符显示序列):

7824 7825
7827 7828 7829
7831 7832 7833 7834 7835 7836
7838 7839 7840 7841 7842 7843 7844 7845
7847

main() {
    int i;
    int pid, pids[1000];
    for (i=0; i<20; i++) {
        if (pid = fork()) {
            //write(1, "PARENT\n", 7);
            pids[i] = pid;
        }
        else {
            fork();
            //write(1, "child\n", 6);
            exit(0);
        }
    }
    for (i=0; i<20; i++) printf("%d\n", pids[i]);
}

【讨论】:

    猜你喜欢
    • 2020-08-08
    • 1970-01-01
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-02
    相关资源
    最近更新 更多