进程控制与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) 收养并回收。