进程创建
100%

进程 · 第 4 课

进程创建

学习 fork、exec、PID 和父进程关系如何参与 Linux 进程创建。

Linux 进程会形成父子关系。Shell 通常先创建子进程,再安排该子进程执行所请求的程序,从而启动外部命令。经典解释会把这项工作分成 forkexec 操作。

使用 `fork` 创建子进程

fork() 系统调用会根据调用进程创建子进程。父进程和子进程都会从 fork 的返回点继续,但获得不同的返回值和不同的 PID。

子进程获得逻辑上独立的进程状态。Linux 最初可以使用写时复制共享物理内存页面,只有某个进程修改页面时才复制。打开的文件描述符会被继承,并引用相同的底层打开文件描述,因此文件偏移等细节可能继续共享。

成功的 fork() 会创建什么?

使用 `execve` 替换程序

execve() 调用会把新程序加载到调用进程中。成功时,它会替换进程映像,不会返回旧程序。PID 保持不变,因为 execve() 不会创建新进程。

因此,许多 shell 命令遵循 fork-exec 模式:

  1. Shell 创建子进程。
  2. 子进程准备重定向和其他执行状态。
  3. 子进程执行所请求的程序。
  4. Shell 根据前台或后台执行选择等待或继续。

库和应用程序可以提供 posix_spawn() 等更高层接口,Linux 也有 clone() 等其他原语。熟悉的 fork-exec 模型仍然有用,但不是唯一可能的接口。

成功执行 execve() 后,进程的 PID 会发生什么?

检查父进程和子进程 ID

PID 标识进程,PPID 标识其父进程。明确请求这些字段:

$ ps -o pid,ppid,stat,cmd

如果 shell 启动 ps,该 shell 的 PID 通常会显示为 ps 进程的 PPID。时机很重要:短生命周期进程可能在单独的观察命令捕获之前就已经退出。

进程列表中的 PPID 表示什么?

PID 1 和重新指定父进程

内核会以 PID 1 启动第一个用户空间进程。根据系统,它可能是 systemd、其他 init 实现,或容器/PID 命名空间中的小型 init。PID 1 会启动并监督部分用户空间环境,还承担特殊的信号和孤儿进程回收职责。

父进程先于子进程退出时,子进程会被重新指定给适当的 subreaper,或其 PID 命名空间中的 init 进程。它不必仅因原父进程结束而终止。

关于 PID 1,哪个说法准确?

课程已完成

你已完成 进程创建

现在,你可以追踪经典的 Linux 进程创建顺序。

  • 使用 fork() 创建具有不同 PID 的子进程。

  • 使用 execve() 替换进程映像而不改变 PID。

  • 读取 PID 和 PPID 以识别父子关系。

  • 认识 PID 1 和 subreaper 是重新指定父进程后的子进程去向。

保存学习进度

创建免费账户即可保存本课进度,并在任意设备上继续学习。

创建免费账户
下一节
返回 进程