在 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 进程的行为。