dede网站维护暂时关闭,网上书城网站开发的目的与意,wordpress 生成gif,手机网站 win8风格【僵尸进程】 目录#xff1a;知识点1. 僵尸进程的定义2. 僵尸进程产生的原因3. 僵尸进程的危害4. 如何避免僵尸进程 代码示例产生僵尸进程的代码示例避免僵尸进程的代码示例#xff08;父进程主动回收#xff09;避免僵尸进程的代码示例#xff08;信号处理#xff09; 运… 【僵尸进程】 目录知识点1. 僵尸进程的定义2. 僵尸进程产生的原因3. 僵尸进程的危害4. 如何避免僵尸进程 代码示例产生僵尸进程的代码示例避免僵尸进程的代码示例父进程主动回收避免僵尸进程的代码示例信号处理 运行结果产生僵尸进程的代码运行结果避免僵尸进程的代码父进程主动回收运行结果避免僵尸进程的代码信号处理运行结果 僵尸进程原理实现方法1. 使用 wait 函数2. 使用 waitpid 函数 代码示例使用 wait 函数使用 waitpid 函数 代码解释会自动释放的资源1. 内存资源2. 文件描述符3. 信号处理函数设置 不会自动释放的资源1. 进程描述符2. 一些共享资源 目录
知识点
1. 僵尸进程的定义
在 Linux 系统中当一个子进程结束运行通过调用 exit 或接收到终止信号它并不会立即从系统中消失。子进程会进入僵尸状态Zombie State此时子进程已经停止执行但它的进程描述符包含进程的退出状态等信息仍然保留在系统中直到其父进程调用 wait 或 waitpid 等系统调用获取其退出状态释放该进程描述符子进程才会真正被销毁。处于这种状态的进程就被称为僵尸进程。
2. 僵尸进程产生的原因
子进程先于父进程结束而父进程没有及时调用 wait 或 waitpid 来回收子进程的资源导致子进程的进程描述符一直保留在系统中从而产生僵尸进程。
3. 僵尸进程的危害
僵尸进程虽然不占用系统的 CPU 资源但它会占用系统的进程表项。如果系统中存在大量的僵尸进程会导致进程表项被耗尽从而无法创建新的进程影响系统的正常运行。
4. 如何避免僵尸进程
父进程主动回收父进程在子进程结束后及时调用 wait 或 waitpid 来回收子进程的资源。信号处理父进程可以通过捕获 SIGCHLD 信号在信号处理函数中调用 wait 或 waitpid 来回收子进程的资源。使用 sigaction 函数结合 sigaction 函数和 SA_NOCLDWAIT 标志避免子进程成为僵尸进程。
代码示例
产生僵尸进程的代码示例
#include stdio.h
#include stdlib.h
#include unistd.hint main() {pid_t pid fork();if (pid 0) {perror(fork);return 1;} else if (pid 0) {// 子进程printf(子进程 (PID%d) 即将退出\n, getpid());exit(0);} else {// 父进程printf(父进程 (PID%d) 继续运行不回收子进程资源\n, getpid());sleep(60); // 父进程休眠 60 秒不回收子进程资源}return 0;
}避免僵尸进程的代码示例父进程主动回收
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/wait.hint main() {pid_t pid fork();if (pid 0) {perror(fork);return 1;} else if (pid 0) {// 子进程printf(子进程 (PID%d) 即将退出\n, getpid());exit(0);} else {// 父进程printf(父进程 (PID%d) 等待子进程退出并回收资源\n, getpid());int status;pid_t child_pid wait(status);if (child_pid 0) {if (WIFEXITED(status)) {printf(子进程 (PID%d) 正常退出退出状态码: %d\n, child_pid, WEXITSTATUS(status));}}}return 0;
}避免僵尸进程的代码示例信号处理
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/wait.h
#include signal.hvoid sigchld_handler(int signum) {int status;pid_t pid;while ((pid waitpid(-1, status, WNOHANG)) 0) {if (WIFEXITED(status)) {printf(子进程 (PID%d) 正常退出退出状态码: %d\n, pid, WEXITSTATUS(status));}}
}int main() {signal(SIGCHLD, sigchld_handler);pid_t pid fork();if (pid 0) {perror(fork);return 1;} else if (pid 0) {// 子进程printf(子进程 (PID%d) 即将退出\n, getpid());exit(0);} else {// 父进程printf(父进程 (PID%d) 继续运行等待子进程退出信号\n, getpid());sleep(60);}return 0;
}运行结果
产生僵尸进程的代码运行结果
子进程 (PID1234) 即将退出
父进程 (PID1233) 继续运行不回收子进程资源在父进程休眠的 60 秒内使用 ps -ef | grep Z 命令可以查看到僵尸进程
USER PID PPID C STIME TTY TIME CMD
youruser 1234 1233 0 10:00 pts/0 00:00:00 [a.out] defunct其中 defunct 表示该进程是僵尸进程。
避免僵尸进程的代码父进程主动回收运行结果
子进程 (PID1234) 即将退出
父进程 (PID1233) 等待子进程退出并回收资源
子进程 (PID1234) 正常退出退出状态码: 0此时使用 ps -ef | grep Z 命令不会查看到僵尸进程。
避免僵尸进程的代码信号处理运行结果
子进程 (PID1234) 即将退出
父进程 (PID1233) 继续运行等待子进程退出信号
子进程 (PID1234) 正常退出退出状态码: 0同样使用 ps -ef | grep Z 命令不会查看到僵尸进程。
僵尸进程
在 Linux 系统中父进程可以通过主动回收子进程资源的方式来避免僵尸进程的产生。下面为你详细介绍相关原理、实现方法以及代码示例。
原理
当子进程结束时它会向父进程发送 SIGCHLD 信号同时进入僵尸状态此时子进程的进程描述符仍然保留在系统中占用系统资源。父进程可以通过调用 wait 或 waitpid 系统调用获取子进程的退出状态并释放其进程描述符从而让子进程彻底从系统中消失。
实现方法
1. 使用 wait 函数
wait 函数会阻塞父进程直到它的任意一个子进程结束。当子进程结束后wait 函数会返回该子进程的进程 ID并将子进程的退出状态存储在 status 参数中。
#include sys/types.h
#include sys/wait.h
#include unistd.h
#include stdio.hpid_t wait(int *status);参数status 是一个指向整数的指针用于存储子进程的退出状态。如果不需要获取退出状态可以将其设置为 NULL。返回值成功时返回结束的子进程的进程 ID出错时返回 -1。
2. 使用 waitpid 函数
waitpid 函数提供了更灵活的子进程回收方式它可以指定要等待的子进程还可以设置非阻塞模式。
#include sys/types.h
#include sys/wait.h
#include unistd.h
#include stdio.hpid_t waitpid(pid_t pid, int *status, int options);参数 pid指定要等待的子进程。取值有以下几种情况 pid 0等待进程 ID 为 pid 的子进程。pid -1等待任意一个子进程等同于 wait 函数。pid 0等待与调用进程同组的任意子进程。pid -1等待进程组 ID 等于 pid 绝对值的任意子进程。 status用于存储子进程的退出状态与 wait 函数的 status 参数相同。options可以设置一些选项常用的选项有 WNOHANG如果没有子进程结束函数立即返回 0而不会阻塞。WUNTRACED如果子进程处于暂停状态函数也会返回。WCONTINUED如果子进程因收到 SIGCONT 信号而继续运行函数也会返回。 返回值 如果 options 中设置了 WNOHANG且没有子进程结束返回 0。成功时返回结束的子进程的进程 ID。出错时返回 -1。
代码示例
使用 wait 函数
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/wait.hint main() {pid_t pid fork();if (pid 0) {perror(fork);return 1;} else if (pid 0) {// 子进程printf(子进程 (PID%d) 即将退出\n, getpid());exit(0);} else {// 父进程printf(父进程 (PID%d) 等待子进程退出并回收资源\n, getpid());int status;pid_t child_pid wait(status);if (child_pid 0) {if (WIFEXITED(status)) {printf(子进程 (PID%d) 正常退出退出状态码: %d\n, child_pid, WEXITSTATUS(status));}}}return 0;
}使用 waitpid 函数
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/wait.hint main() {pid_t pid fork();if (pid 0) {perror(fork);return 1;} else if (pid 0) {// 子进程printf(子进程 (PID%d) 即将退出\n, getpid());exit(0);} else {// 父进程printf(父进程 (PID%d) 等待子进程退出并回收资源\n, getpid());int status;pid_t child_pid waitpid(pid, status, 0);if (child_pid 0) {if (WIFEXITED(status)) {printf(子进程 (PID%d) 正常退出退出状态码: %d\n, child_pid, WEXITSTATUS(status));}}}return 0;
}代码解释 在上述代码中首先使用 fork 函数创建一个子进程。 子进程打印一条信息后调用 exit 函数退出。父进程打印一条信息后调用 wait 或 waitpid 函数等待子进程退出并获取其退出状态。使用 WIFEXITED 宏判断子进程是否正常退出如果是则使用 WEXITSTATUS 宏获取子进程的退出状态码并打印。 通过这种方式父进程可以及时回收子进程的资源避免僵尸进程的产生。 子进程在退出时会自动释放一部分资源但并非所有资源都会自动释放下面为你详细介绍
会自动释放的资源
1. 内存资源
栈和堆内存子进程在运行过程中在栈上分配的局部变量和在堆上通过malloc、calloc、realloc等函数分配的内存在子进程退出时会被自动释放。例如在子进程中使用malloc分配了一块内存用于存储数据当子进程退出时操作系统会回收这块内存防止内存泄漏。数据段和代码段子进程的代码段存储程序的可执行指令和数据段存储全局变量和静态变量所占用的内存空间也会在子进程退出时被释放。
2. 文件描述符
子进程在运行过程中打开的文件描述符如文件、套接字等在子进程退出时会被操作系统自动关闭 例如子进程打开了一个文件进行读写操作当子进程退出时该文件描述符会被关闭相应的文件资源会被释放。
3. 信号处理函数设置
子进程所设置的信号处理函数等相关设置在其退出时会失效操作系统会清理这些与子进程相关的信号处理信息。
不会自动释放的资源
1. 进程描述符
子进程退出后其进程描述符包含进程的状态信息、退出状态、资源使用统计等并不会自动释放。子进程会进入僵尸状态Zombie State此时它的进程描述符仍然保留在系统中直到其父进程调用wait或waitpid等系统调用获取其退出状态释放该进程描述符子进程才会真正从系统中消失。如果父进程没有及时回收子进程的进程描述符就会产生僵尸进程。
2. 一些共享资源
共享内存如果子进程使用了共享内存通过shmget、shmat等函数创建或关联在子进程退出时共享内存本身不会自动释放。共享内存是多个进程可以共享的内存区域子进程的退出不会影响其他进程对共享内存的使用需要显式地调用shmdt分离共享内存和shmctl删除共享内存等函数来释放共享内存资源。信号量子进程使用的信号量通过semget、semop等函数操作在其退出时也不会自动释放。信号量是用于进程间同步的机制需要显式地调用semctl等函数来删除信号量集。
综上所述虽然子进程在退出时会自动释放一部分资源但对于进程描述符和一些共享资源需要父进程或其他进程进行显式的处理以确保系统资源的正确释放和回收。