fork系统调用是如何工作的?

mik*_*mik 4 process c posix fork

如果我们看一下这个例子

#include <stdio.h>
#include <unistd.h>

void main(){
  int pi_d ;
  int pid ;
  pi_d = fork();
  if(pi_d == 0){
    printf("Child Process B:\npid :%d\nppid:%d\n",getpid(),getppid());
  }
  if(pi_d > 0){
    pid = fork();
    if(pid > 0){
      printf("\nParent Process:\npid:%d\nppid :%d\n",getpid(),getppid());
    }
    else if(pid == 0){
      printf("Child Process A:\npid :%d\nppid:%d\n",getpid(),getppid());
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

对我来说,这看起来会无限期地创建进程,因为当我们分叉一个进程时,会创建父进程的副本。这样程序代码就被克隆了。

这意味着每个新进程都运行相同的代码;因此,它调用pi_d = fork(),等等。

我在这里缺少什么?

A.B*_*A.B 7

引用POSIX fork 定义(粗体强调我的):

返回值

成功完成后,fork() 将向子进程返回 0,并向父进程返回子进程的进程 ID。 两个进程都应继续从该函数执行fork()。否则,应返回-1给父进程,不会创建子进程,并errno应设置以指示错误。

OP 写道:

这意味着,对于每个新进程,它都会运行相同的代码

成功完成fork()并从中返回后,父级和子级将立即恢复fork():第一个将不会再次执行fork(),然后第一个或第二个将不会再次执行fork(),因为此代码中没有循环允许这种情况发生。

假设没有发生错误(没有检查):

  • 父分叉
    • 如果是子显示器的话Child Process B
    • 否则,如果是父级,则再次分叉
      • 如果它(再次)是父级,则显示Parent Process
      • 如果是父母的第二个孩子,则显示Child Process A

由于无法保证子级或父级中的哪一个会按照精确的执行顺序击败另一个,因此 3 个输出可以按任何顺序发生或混合发生(但在给定的特定操作系统上,一个显示顺序应该比其他显示顺序更频繁地发生,并且Child Process B具有领先优势可能会首先显示)。

  • 我认为OP的一个关键误解是他们似乎认为`fork`的作用就像当前可执行文件的`exec`(即启动一个新进程),而它实际上“复制”程序的当前状态(堆栈,内存) ,文件句柄),唯一的区别是这个答案中所述的区别:一个进程从当前调用返回“0”,另一个进程返回一个(正)PID。 (6认同)