fork() 通过复制调用进程来创建一个子进程,并将一个进程从被调用的位置一分为二。子进程和父进程在不同的内存空间中运行1)。在fork() 时,两个内存空间具有相同的内容。也就是说,子进程中的变量值与fork()时父进程的值相同。
在for循环的第一次迭代中:
pid[i] = fork();
// this will create child process and both parent and child process proceed with next statement
if ( pid[i] == 0){ // only child process will enter to this if block
printf("[child] pid %d from [parent] pid %d\n",getpid(),getppid());
}
打印的输出:
[child] pid 11310 from [parent] pid 11309
在执行for循环体后,由于i++,循环控制变量i的值在父进程地址空间和子进程地址空间都会递增。
因此,在第二次迭代中,i 的值在父地址空间和子地址空间中都是 1。
现在父 (PID: 11309) 和子 (PID: 11310) 都将执行 for 循环体,并且都将创建一个子进程。这就是子进程(PID: 11310) 正在创建另一个子进程(PID: 11312) 的原因。
11309----- --|
| | |---------> First iteration
11310 | --| --|
| | |---> Second iteration
11312 11311 --|
在第三次迭代中,i 在所有4 进程中的值将是2,循环条件i<2 将导致false,并且所有进程都将退出。
您的代码中有一个严重问题 - 如果父进程完成运行并在子进程之前退出会发生什么?
在这种情况下,子进程将变为orphan process,并且您可能将父 PID 设为1,而不是原始父进程 ID,因为孤立进程可能重新成为 init 进程的父进程,该进程通常被分配PID1。
要克服这个问题,您必须在退出之前为其所有子进程设置父wait。
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
pid_t pid;
// You can take number of child process to be create as input from user
for (int i = 0; i < 2; i++) {
pid = fork();
if (pid == 0) {
printf("[child] pid %d from [parent] pid %d\n", getpid(), getppid());
break;
}
}
if (pid != 0) {
int cpid;
int status;
while ((cpid = wait(&status)) > 0)
printf("Parent (%d): child (%d) exited with status 0x%.4x\n", (int)getpid(), cpid, status);
}
return 0;
}
1) 有一个称为Copy-on-Write的概念,这是一种优化,其中设置了页表,以便父进程和子进程开始共享所有相同的内存,并且仅在需要时复制任一进程写入的页面。这意味着父进程和子进程共享相同数据的副本,并且一旦它们中的任何一个进行写入,就会生成副本,并且一个进程的内存中的任何更改在另一个进程中不可见。