fork系统调用到底是如何工作的

fork系统调用到底是如何工作的

我有一个关于 fork 系统调用的非常具体的问题。我有这段代码:

int main (void) 
{
    for (int i = 0; i < 10; i++) {
        pid_t pid = fork ();

        if ( !pid ) {
            printf("CHILD | PID: %d, PPID: %d\n", getpid(), getppid());
            _exit(i + 1);
        }

    }

    for (int i = 0; i < 10; i++) {
        int status;
        waitpid(-1, &status, 0);

        if (WIFEXITED(status)) {
            printf("IM %d AND CHILD WITH EXIT CODE %d TERMINATED\n",
                    getpid(), WEXITSTATUS(status));

        } 
        else {
            printf("ERROR: CHILD NOT EXITED\n");
        }
    }

    return 0;
}

产生以下输出:

CHILD | PID: 3565, PPID: 3564
CHILD | PID: 3566, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 1 TERMINATED
IM 3564 AND CHILD WITH EXIT CODE 2 TERMINATED
CHILD | PID: 3573, PPID: 3564
CHILD | PID: 3567, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 9 TERMINATED
IM 3564 AND CHILD WITH EXIT CODE 3 TERMINATED
CHILD | PID: 3568, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 4 TERMINATED
CHILD | PID: 3569, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 5 TERMINATED
CHILD | PID: 3570, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 6 TERMINATED
CHILD | PID: 3571, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 7 TERMINATED
CHILD | PID: 3572, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 8 TERMINATED
CHILD | PID: 3574, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 10 TERMINATED

这让我想知道 fork 到底是如何工作的以及新进程真正执行的代码是什么。看着上面的输出结果,我无法理解:

  1. 如何第二个循环之前打印首先是为了完成所有迭代?我也注意到了这一点第二个为总是由父进程执行,这让我想知道 while on首先for循环, if pid != 0(表示父进程调用)第二个循环被执行(?)
  2. 为什么CHILD进程没有按PID排序打印?

那么,最重要的是,fork 到底是如何工作的以及谁执行什么?

答案1

当您执行 时fork,内核创建一个新进程,它是分叉进程的副本,并且两个进程在之后继续执行fork(返回代码显示是否发生错误,以及运行的代码是父进程还是子进程)。这个“继续执行”部分并不一定立即发生:内核只是将新进程添加到运行队列中,它最终会被调度并运行,但不一定立即发生。

这解释了您所询问的两种行为:

  • 由于新进程不一定会立即调度,因此父进程可能会在任何子进程有机会运行之前继续运行;
  • 创建顺序对运行队列没有太大(如果有)影响,因此不能保证子进程将按照它们创建的顺序运行。

相关内容