在 Linux 系统中,fork() 和 exec() 是进程管理的两个核心系统调用,它们的区别和协作关系如下:
fork() 返回处开始执行,与父进程并发运行。示例:
pid_t pid = fork();
if (pid == 0) {
printf("Child process (PID: %d)\n", getpid());
} else {
printf("Parent process (Child PID: %d)\n", pid);
}
execl(), execv(), execvp() 等(参数传递方式不同)。示例:
execl("/bin/ls", "ls", "-l", NULL); // 替换为 `ls -l`
printf("This line is never reached!"); // 除非 exec 失败
| 特性 | fork() |
exec() |
|---|---|---|
| 进程创建 | 创建新进程(子进程) | 不创建进程,替换当前进程 |
| 资源复制 | 复制父进程资源 | 完全替换为新程序的资源 |
| 执行流 | 父子进程并发执行相同代码 | 原进程代码被新程序替代 |
| 典型用途 | 多进程并发 | 启动外部程序 |
通常结合使用 fork() + exec() 来启动新程序:
1. fork():创建子进程。
2. exec():在子进程中替换为新程序。
3. 父进程:可能通过 wait() 等待子进程结束。
示例:
pid_t pid = fork();
if (pid == 0) {
execl("/bin/ls", "ls", "-l", NULL); // 子进程执行 ls
perror("exec failed"); // 仅当 exec 失败时执行
exit(1);
} else {
wait(NULL); // 父进程等待子进程结束
}
Q: 为什么需要先 fork() 再 exec()?
A: fork() 提供并发能力,exec() 允许执行不同程序。直接调用 exec() 会终止原进程。
Q: fork() 的性能开销?
A: 写时复制(COW)技术减少了内存复制的开销。
Q: 如何避免僵尸进程?
A: 父进程需调用 wait() 或使用信号处理(如 SIGCHLD)。
通过理解 fork() 和 exec() 的区别与协作,可以更灵活地控制 Linux 进程的行为。