进程控制与Fork

Related: 进程与上下文切换

1. 进程状态机

从程序员视角看,进程有三种状态:

  • 运行 (Running): 正在 CPU 上执行,或者在就绪队列中等待调度。
  • 停止 (Stopped): 被信号 (如 SIGTSTP/Ctrl+Z) 挂起,直到收到 SIGCONT 信号。
  • 终止 (Terminated): 永久停止。原因:1. 收到终止信号;2. 从 main 返回;3. 调用 exit()

2. Fork: 分身术

pid_t fork(void)

  • 一次调用,两次返回:
    • 父进程返回 子进程的 PID
    • 子进程返回 0
  • 并发执行: 父子进程是并发运行的独立指令流。不能假设谁先执行(拓扑排序)。
  • 相同但独立的地址空间: 子进程拥有父进程内存(栈、堆、数据段)的副本Copy-on-Write (写时复制) 机制保证了效率。
  • 共享文件: 子进程继承父进程打开的所有文件描述符(stdout 指向同一个终端)。

3. Execve: 夺舍

int execve(filename, argv, envp)

  • 功能: 在当前进程中加载并运行一个新的程序。
  • 特性:
    • 覆盖当前进程的代码、数据、栈。
    • 保留 PID
    • 一次调用,从不返回(除非出错)。
  • Shell 逻辑: Shell 先 fork 一个子进程,然后在子进程里 execve 用户输入的命令。

4. Waitpid: 收尸义务

pid_t waitpid(pid, &status, options)

  • 僵尸进程 (Zombie): 终止但未被父进程回收的进程。它仍然占用 PID 和内核表项。
  • 回收: 父进程必须调用 waitpid 来回收僵尸子进程。
  • Init 进程: 如果父进程死了,孤儿进程由 init (PID 1) 收养并回收。