父进程创建了子进程,子进程的PCB是拷贝的父进程的PCB,内容一致。并且数据段,代码段,子进程是与父进程共享的(此时权限会被设为只读),当子进程要对其进行修改,此时会发生写时拷贝,将子进程要修改的数据,拷贝一份,单独交给子进程(这一部分权限可写,可读)。



main返回
exit
_exit

wait 和 waitpid 是 Unix/Linux 系统中用于处理子进程状态变化的系统调用,通常在 C 或 C++ 编程里使用。下面为你详细介绍:
wait 函数#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);wait 函数会让调用进程阻塞,直到它的任意一个子进程终止。若子进程已经终止,wait 会立即返回。返回值是终止子进程的进程 ID,若出错则返回 -1。status 是一个整型指针,用于存储子进程的终止状态。若不关心终止状态,可将其设为 NULL。#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
} else if (pid == 0) {
// 子进程
printf("Child process is running.\n");
sleep(2);
printf("Child process is exiting.\n");
exit(0);
} else {
// 父进程
int status;
pid_t child_pid = wait(&status);
if (child_pid > 0) {
if (WIFEXITED(status)) {
printf("Child process %d exited normally with status %d.\n", child_pid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Child process %d was terminated by signal %d.\n", child_pid, WTERMSIG(status));
}
}
}
return 0;
}waitpid 函数#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);waitpid 函数的功能与 wait 类似,不过它可以指定等待某个特定的子进程,还能通过 options 参数来控制等待行为。返回值是终止子进程的进程 ID,若指定 WNOHANG 且没有子进程终止则返回 0,若出错则返回 -1。pid:用于指定要等待的子进程的进程 ID。若 pid > 0,则等待指定进程 ID 的子进程;若 pid == -1,则等待任意子进程,等同于 wait;若 pid == 0,则等待与调用进程在同一进程组的任意子进程;若 pid < -1,则等待进程组 ID 等于 pid 绝对值的任意子进程。status:和 wait 中的 status 作用相同,用于存储子进程的终止状态。options:是一个位掩码,可使用 WNOHANG 让 waitpid 非阻塞地返回,即若没有子进程终止则立即返回 0;还可使用 WUNTRACED 来关注因收到信号而停止的子进程。#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
} else if (pid == 0) {
// 子进程
printf("Child process is running.\n");
sleep(2);
printf("Child process is exiting.\n");
exit(0);
} else {
// 父进程
int status;
pid_t child_pid = waitpid(pid, &status, WNOHANG);
if (child_pid == 0) {
printf("No child process has exited yet.\n");
} else if (child_pid > 0) {
if (WIFEXITED(status)) {
printf("Child process %d exited normally with status %d.\n", child_pid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Child process %d was terminated by signal %d.\n", child_pid, WTERMSIG(status));
}
}
}
return 0;
}wait 只能等待任意子进程终止,而 waitpid 能指定等待某个特定的子进程,并且可以控制等待行为,如非阻塞等待。wait 是阻塞调用,会一直等待直到有子进程终止;waitpid 可通过 WNOHANG 选项实现非阻塞调用。替换原理 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

替换函数





execvpe 是 Unix/Linux 系统里 exec 函数族中的一员,该函数族的作用是在当前进程的上下文中执行新程序,替换当前进程的映像。下面详细介绍 execvpe 函数。
#include <unistd.h>
#include <stdlib.h>
int execvpe(const char *file, char *const argv[], char *const envp[]);file:指向要执行的程序文件名的指针。此文件名无需是完整路径,execvpe 会依据 PATH 环境变量来查找该程序。argv:指向参数数组的指针,该数组里的每个元素都是一个指向字符串的指针,代表传递给新程序的参数。数组的第一个元素通常是新程序的名称,最后一个元素必须为 NULL,以此标记参数列表的结束。envp:指向环境变量数组的指针。数组中的每个元素都是形如 name=value 的字符串,用于为新程序设置环境变量。execvpe 函数会用指定的程序替换当前进程的映像。若调用成功,它不会返回;只有在调用失败时,才会返回 -1,并设置相应的错误码。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
// 定义要执行的程序文件名
const char *file = "ls";
// 定义传递给程序的参数数组
char *argv[] = {
"ls",
"-l",
NULL
};
// 定义环境变量数组
char *envp[] = {
"PATH=/bin:/usr/bin",
"HOME=/home/user",
NULL
};
// 调用 execvpe 函数执行新程序
int result = execvpe(file, argv, envp);
// 如果 execvpe 调用失败,会执行到这里
if (result == -1) {
perror("execvpe");
return 1;
}
return 0;
}execvpe 函数执行了 ls 程序,并且传递了 -l 参数。PATH 和 HOME。execvpe 调用成功,当前进程会被 ls 程序替代,输出文件列表。若调用失败,则会输出错误信息。execvpe 调用成功后不会返回,所以调用之前的代码会被执行,而调用之后的代码只有在调用失败时才会执行。file 参数不是完整路径,execvpe 会依据 envp 数组里的 PATH 环境变量查找程序。若 envp 中未包含 PATH,则使用当前进程的 PATH 环境变量。NULL 结尾。