设计大型网站建设,网站营销看法,开发一个app难吗,南山制作网站公司僵尸进程是什么#xff1f;
僵尸进程的定义#xff1a;对于多进程程序#xff0c;当子进程结束运行但父进程还未读取其退出状态时#xff0c;子进程就处于僵尸态。此时#xff0c;内核不会立即释放该子进程的进程表表项#xff0c;以满足父进程后续查询子进程退出信息的…僵尸进程是什么
僵尸进程的定义对于多进程程序当子进程结束运行但父进程还未读取其退出状态时子进程就处于僵尸态。此时内核不会立即释放该子进程的进程表表项以满足父进程后续查询子进程退出信息的需求产生原因子进程运行结束后父进程若没有及时获取其退出状态子进程就会一直处于僵尸态当父进程提前结束或异常终止而子进程继续运行时子进程的 PPID父进程 ID会被操作系统设置为 1即由 init 进程接管。在父进程退出后到子进程退出前这段时间子进程也处于僵尸态。僵尸进程的危害僵尸进程会一直占据内核资源而内核资源是有限的。如果大量产生僵尸进程可能会导致系统资源耗尽影响系统性能。
处理僵尸进程的函数 pid_t wait(int *stat_loc) wait 函数会阻塞调用它的进程通常是父进程直到该进程的任意一个子进程结束运行。这意味着调用 wait 后父进程会暂停执行等待子进程完成任务。 当有子进程结束时wait 函数返回结束运行的子进程的进程 IDPID同时将该子进程的退出状态信息存储在 stat_loc 参数指向的内存位置。退出状态信息包含了子进程是如何结束的例如是正常退出还是因信号终止等。 通过 sys/wait.h 头文件中定义的宏来解析 stat_loc 中的退出状态信息
WIFEXITED(stat_val)用于判断子进程是否正常结束。如果子进程正常结束该宏返回一个非零值即真。WEXITSTATUS(stat_val)当 WIFEXITED 返回非零值时使用此宏可以获取子进程的退出码。子进程通过 exit 函数或从 main 函数返回时设置的退出码可以通过这个宏获取。WIFSIGNALED(stat_val)如果子进程是因为一个未捕获的信号而终止此宏返回一个非零值。WTERMSIG(stat_val)当 WIFSIGNALED 返回非零值时该宏返回导致子进程终止的信号值。例如如果子进程因接收到 SIGTERM 信号而终止WTERMSIG 将返回 SIGTERM 的值。WIFSTOPPED(stat_val)若子进程被暂停例如收到 SIGSTOP 信号此宏返回一个非零值。WSTOPSIG(stat_val)当 WIFSTOPPED 返回非零值时该宏返回导致子进程暂停的信号值。 示例代码如下
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/types.h
#include sys/wait.hint main() {pid_t pid;int status;pid fork();if (pid -1) {perror(fork);return 1;} else if (pid 0) {// 子进程printf(Child process: My PID is %d\n, (int)getpid());exit(10); // 子进程正常退出退出码为10} else {// 父进程pid_t terminated_pid wait(status);if (terminated_pid -1) {perror(wait);return 1;}if (WIFEXITED(status)) {printf(Child %d exited normally with exit code %d\n, (int)terminated_pid, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf(Child %d terminated by signal %d\n, (int)terminated_pid, WTERMSIG(status));}}return 0;
} 输出如下 pid_t waitpid(pid_t pid, int *stat_loc, int options) waitpid 函数提供了比 wait 函数更灵活的等待方式。它可以等待由 pid 参数指定的特定子进程。
pid 0等待进程 ID 为 pid 的子进程。pid -1等待任意一个子进程此时 waitpid 的行为和 wait 函数相同。pid 0等待与调用进程同组的任意子进程。pid -1等待进程组 ID 等于 pid 绝对值的任意子进程。 与 wait 函数类似waitpid 函数返回结束运行的子进程的 PID并将子进程的退出状态信息存储在 stat_loc 参数指向的内存位置同样可以使用 sys/wait.h 中的宏来解析退出状态。 options 参数可以控制 waitpid 函数的行为。最常用的取值是 WNOHANG当 options 取值为 WNOHANG 时waitpid 调用将是非阻塞的。如果 pid 指定的目标子进程还没有结束或意外终止则 waitpid 立即返回 0如果目标子进程确实正常退出了则 waitpid 返回该子进程的 PID。若 waitpid 调用失败返回 -1 并设置 errno 示例代码如下
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/types.h
#include sys/wait.hint main() {pid_t pid;int status;pid fork();if (pid -1) {perror(fork);return 1;} else if (pid 0) {// 子进程printf(Child process: My PID is %d\n, (int)getpid());sleep(2); // 模拟子进程执行一些任务exit(10); // 子进程正常退出退出码为10} else {// 父进程while (1) {pid_t terminated_pid waitpid(pid, status, WNOHANG);if (terminated_pid -1) {perror(waitpid);return 1;} else if (terminated_pid 0) {// 子进程还未结束printf(Child is still running...\n);sleep(1);//模拟父进程处理自己的任务} else {if (WIFEXITED(status)) {printf(Child %d exited normally with exit code %d\n, (int)terminated_pid, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf(Child %d terminated by signal %d\n, (int)terminated_pid, WTERMSIG(status));}break;}}}return 0;
} 输出如下 讲解一下示例代码采用的是轮询的方式检测子进程是否已经退出如果未退出waitpid()会返回0进行下次轮检测如果子进程退出了会打印子进程的退出码。这样做的好处是父进程不必阻塞等待子进程退出它可以边等待边处理自己的任务。
处理僵尸进程更好的方式利用SIGCHLD信号 不断的轮询子进程的状态绝非明智之举。要在事件当然了这里的事件就是子进程退出已经发生的情况下执行非阻塞调用才能提高程序的效率。 当一个进程结束时它会给其父进程发送一个SIGCHLD信号。因此父进程可以捕获这个信号并在信号处理函数中调用waitpid函数来处理结束的子进程从而避免僵尸进程的产生。也就是说SIGCHLD信号触发相当于通知父进程你的子进程已经退出了。 示例代码如下
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/types.h
#include sys/wait.h
#include signal.h// SIGCHLD信号处理函数
static void handle_child(int sig) {pid_t pid;int stat;// 使用waitpid循环处理已结束的子进程while ((pid waitpid(-1, stat, WNOHANG)) 0) {if (WIFEXITED(stat)) {printf(Child %d exited normally with exit code %d\n, (int)pid, WEXITSTATUS(stat));} else if (WIFSIGNALED(stat)) {printf(Child %d terminated by signal %d\n, (int)pid, WTERMSIG(stat));}}
}int main() {pid_t pid;// 注册SIGCHLD信号处理函数struct sigaction sa;sa.sa_handler handle_child;sigemptyset(sa.sa_mask);sa.sa_flags SA_RESTART;if (sigaction(SIGCHLD, sa, NULL) -1) {perror(sigaction);exit(1);}// 创建子进程pid fork();if (pid -1) {perror(fork);exit(1);} else if (pid 0) {// 子进程printf(Child process: My PID is %d\n, (int)getpid());sleep(2); // 模拟子进程执行一些任务exit(10); // 子进程正常退出退出码为10} else {// 父进程printf(Parent process: My PID is %d, Child PID is %d\n, (int)getpid(), (int)pid);// 父进程可以继续执行其他任务while (1) {printf(Parent is doing other things...\n);sleep(1);}}return 0;
} 输出结果如下 对于初学者来说看这段代码有些吃力建议大家在具备了进程信号的知识的前提下再进行阅读。
什么是孤儿进程 孤儿进程指的是父进程在子进程之前终止导致子进程失去了父进程的管理和控制。此时这些子进程会被 init 进程进程 ID 为 1收养。init 进程是 Linux 系统启动后创建的第一个用户态进程它负责管理系统中所有孤儿进程的生命周期。 如果父进程执行完毕或因异常情况提前终止而它创建的子进程还在运行这些子进程就会成为孤儿进程。 写段代码举个例子
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/types.hint main() {pid_t pid fork();if (pid -1) {perror(fork);return 1;} else if (pid 0) {// 子进程printf(Child process: My PID is %d, My PPID is %d\n, (int)getpid(), (int)getppid());sleep(5); // 模拟子进程执行任务printf(Child process: After sleeping, My PPID is %d\n, (int)getppid());} else {// 父进程printf(Parent process: My PID is %d, Child PID is %d\n, (int)getpid(), (int)pid);// 父进程提前结束return 0;}return 0;
} 输出结果如下