fork 创建进程

fork 是Unix中创建新进程的唯一系统调用,其行为独特且精妙。

基本行为:调用一次,返回两次。在父进程中,fork 返回新创建子进程的PID;在子进程中,fork 返回 0。通过返回值区分父子进程。

写时复制(Copy-on-Write):子进程创建时并不真正复制父进程的物理内存,而是共享同一物理页,但页表标记为只读。当任一进程尝试写入时,触发缺页故障,内核分配新页并复制数据,然后将页表权限改为可写。这种延迟复制策略极大减少了 fork 的开销,特别是当子进程立即调用 execve 时——子进程根本不需要父进程的数据副本。

子进程状态:子进程是父进程的完全拷贝,包括代码段、数据段、堆、栈、打开文件表、信号处理设置等。但子进程拥有独立的PID、独立的内存空间(逻辑上完全独立)。

执行顺序不确定性:父子进程是并发执行的,它们的指令交错顺序由操作系统调度器决定。虽然通常父进程先执行以减少调度开销,但从程序正确性角度不应依赖任何特定的执行顺序。

示例

pid_t pid = fork();
if (pid == 0) {  /* 子进程 */
    printf("child: %d\n", ++x);
} else {         /* 父进程 */
    printf("parent: %d\n", --x);
}

父进程和子进程中的 x 是各自独立的副本,修改互不影响。

链接到