在操作系统中,fork() 函数是一个非常重要的系统调用,它允许创建一个新的进程,这个新进程是当前进程的一个副本。掌握 fork() 函数不仅是操作系统学习的基础,也是许多编程挑战和面试题的焦点。本文将围绕 fork() 函数,探讨一些经典的习题,并提供详细的解答攻略。
习题一:fork() 函数的返回值
问题:当调用 fork() 函数时,它返回什么值?在父进程中返回什么,在子进程中返回什么?
解答:
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t pid = fork();
if (pid == -1) {
// fork失败
perror("fork failed");
return 1;
} else if (pid == 0) {
// 子进程
printf("I am the child process, PID: %d\n", getpid());
return 0;
} else {
// 父进程
printf("I am the parent process, PID: %d\n", getpid());
}
return 0;
}
在父进程中,fork() 返回子进程的PID。在子进程中,fork() 返回0。如果fork()调用失败,则返回-1。
习题二:如何判断是父进程还是子进程
问题:如何在程序中判断当前进程是父进程还是子进程?
解答:
通过检查 fork() 函数的返回值。如果返回值是0,那么当前进程是子进程;否则,是父进程。
习题三:父子进程共享资源
问题:在父子进程中,如何共享资源?
解答:
父子进程共享内存空间,但是请注意,子进程对父进程的内存修改不会影响父进程,反之亦然。
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int main() {
int shared_data = 10;
pid_t pid = fork();
if (pid == 0) {
// 子进程
shared_data *= 2; // 修改共享数据
printf("Child: shared_data = %d\n", shared_data);
exit(0);
} else {
// 父进程
wait(NULL); // 等待子进程结束
printf("Parent: shared_data = %d\n", shared_data);
}
return 0;
}
在这个例子中,父进程和子进程共享 shared_data 变量。当子进程修改这个变量时,父进程也能看到这个修改。
习题四:如何避免僵尸进程
问题:在 fork() 调用后,如何避免产生僵尸进程?
解答:
在父进程中,使用 wait() 或 waitpid() 等待子进程结束。这可以确保子进程结束后,其资源会被释放,从而避免产生僵尸进程。
pid_t pid = fork();
if (pid == 0) {
// 子进程
// 执行子进程的代码
exit(0);
} else {
// 父进程
wait(NULL); // 等待子进程结束
}
总结
fork() 函数是操作系统中的一个关键特性,它允许进程的创建和资源共享。通过上述经典习题的解答,我们可以更好地理解 fork() 函数的工作原理及其应用。在实际编程中,正确使用 fork() 函数可以避免许多潜在的问题,例如僵尸进程的产生。
