讲解这一主题的帖子很多,但是对于初学者来说依然很难理解。所以本文会先贴出完整的实例代码,然后逐句讲解。重点在于理解函数的工作逻辑。读者可以直接从代码段后开始阅读。
#include
#include
#include
#include
int main() {
pid_t pid = fork(); // 创建一个子进程
if (pid < 0) {
// 如果 fork() 失败
perror("fork failed");
exit(1);
} else if (pid == 0) {
// 子进程逻辑
printf("Child process (PID: %d) is running.\n", getpid());
exit(42); // 子进程以状态码 42 退出
} else {
// 父进程逻辑
int status;
pid_t child_pid = wait(&status); // 等待子进程完成
printf("Parent process: Child (PID: %d) terminated.\n", child_pid);
if (WIFEXITED(status)) {
// 检查子进程是否正常退出
printf("Child exited with status: %d\n", WEXITSTATUS(status));
} else {
printf("Child did not exit normally.\n");
}
}
return 0;
}
首先要理解代码,第一行:pid_t pid = fork();
这里pid_t
是一个数据类型,在 POSIX 标准中定义,用于表示进程的 ID。际实现中通常是一个整数类型。pid_t pid
定义了一个变量 pid
,用于存储 fork()
的返回值。pid
将用来标识当前进程或子进程。
fork()
是一个系统调用,用于创建一个新的子进程。调用 fork()
后,系统会复制当前进程,形成两个几乎完全相同的进程(父进程和子进程)。这两个进程从 fork()
返回点开始,分别继续执行,但它们的返回值不同。在 父进程 中,fork()
返回 子进程的 PID。在 子进程 中,fork()
返回 0。
重点来了:父进程就是你写的这个代码在执行时,操作系统分配给它的初始进程。当程序运行时,操作系统会启动一个进程来执行它的代码。从程序的起点main()开始执行。
运行你的程序最初只有一个进程,从第一行代码开始执行。当程序运行到 fork()
之前,整个程序的所有逻辑都是父进程在执行。
fork()
系统调用会创建一个新的子进程,此时,操作系统中有两个进程在运行这段代码:父进程:原来的进程。子进程:新创建的进程,它从 fork()
调用返回的位置 开始执行代码,返回点是指代码中调用 fork()
的那一行,而不是重新从程序的起点main()
运行。
讲的更具体一些就是,当 fork()
被调用时,操作系统会:复制父进程的内存空间(包括代码段、数据段、栈等)。复制父进程的寄存器状态,包括程序计数器(PC
)、栈指针(SP
)、通用寄存器的值等。因为此时PC
保存的是下一条指令地址,PC
的值指向 fork()
系统调用的下一条指令。子进程从父进程那里复制了 PC
,因此它从 fork()
调用返回的位置开始执行。
此时父子进程从 fork()
的返回点开始执行,pid
被赋值为子进程的 PID,例如 12345
。执行 if (pid > 0)
块。子进程复制了父进程的 PC
,所以从 fork()
的返回点开始执行。操作系统在子进程中将 fork()
的返回值设置为 0,
即pid
被赋值为 0,
执行 else if (pid == 0)
块。
理解了这些部分,wait()的作用就很容易看懂了。 wait()的功能是让父进程等待子进程的状态变化(如子进程退出),然后返回已退出的子进程的 PID。如果出错(如没有子进程),wait()
返回 -1。
子进程在运行过程中,任何状态变化(退出、被信号终止、暂停等)都会向操作系统内核报告。内核会记录这些状态变化,并将子进程的状态保存在数据结构中(如进程控制块,PCB)。当父进程调用 wait()
时:内核检查是否有子进程的状态发生变化。如果有变化,wait()
将子进程的相关信息返回给父进程。
int status;
pid_t child_pid = wait(&status);
这两行意思就是获取退出子进程的 PID(存储在 child_pid
中)。同时将子进程的退出状态保存到变量 status
。wait()
的参数是用来接收子进程的退出状态(如退出码或信号信息)。如果你不关心退出状态,可以传 NULL
。
大家可以试着去编译执行示例代码。我自己运行的结果是:
This is the child process. My PID: 1237
This is the parent process. Child PID: 1237
Child exited with status: 42