南京网站制作费用,企业微商城网站建设,wordpress 内存占用,自己做代练网站目录
1、什么是僵尸进程#xff1f;
2、僵尸进程的目的
3、怎么避免僵尸进程#xff1f;
4、僵尸进程的处理方法
4.1 wait#xff08;#xff09;连接
4.2 waitpid#xff08;#xff09;函数 1、什么是僵尸进程#xff1f; 首先内核会释放终止进程(调用了 exit …目录
1、什么是僵尸进程
2、僵尸进程的目的
3、怎么避免僵尸进程
4、僵尸进程的处理方法
4.1 wait连接
4.2 waitpid函数 1、什么是僵尸进程 首先内核会释放终止进程(调用了 exit 系统调用)所使用的所有存储区关闭所有打开的文件 等但内核为每一个终止子进程保存了一定量的信息。这些信息至少包括进程 ID进程的终止状 态以及该进程使用的 CPU 时间所以当终止子进程的父进程调用 wait 或 waitpid 时就可以得 到这些信息。 而僵尸进程就是指一个进程执行了 exit 系统调用退出而其父进程并没有为它收尸(调用 wait 或 waitpid 来获得它的结束状态)的进程。 任何一个子进程(init 除外)在 exit 后并非马上就消失而是留下一个称外僵尸进程的数据结构 等待父进程处理。这是每个子进程都必需经历的阶段。另外子进程退出的时候会向其父进程发送一 个 SIGCHLD 信号。
2、僵尸进程的目的 设置僵死状态的目的是维护子进程的信息以便父进程在以后某个时候获取。这些信息至少包 括进程 ID进程的终止状态以及该进程使用的 CPU 时间所以当终止子进程的父进程调用 wait 或 waitpid 时就可以得到这些信息。如果一个进程终止而该进程有子进程处于僵尸状态那么 它的所有僵尸子进程的父进程 ID 将被重置为 1init 进程。继承这些子进程的 init 进程将清 理它们也就是说 init 进程将 wait 它们从而去除它们的僵尸状态。
3、怎么避免僵尸进程 1.通过 signal(SIGCHLD, SIG_IGN)通知内核对子进程的结束不关心由内核回收。如果不 想让父进程挂起可以在父进程中加入一条语句signal(SIGCHLD,SIG_IGN);表示父进程忽略 SIGCHLD 信号该信号是子进程退出的时候向父进程发送的。 2.父进程调用 wait/waitpid 等函数等待子进程结束如果尚无子进程退出 wait 会导致父进 程阻塞。waitpid 可以通过传递 WNOHANG 使父进程不阻塞立即返回。 3.如果父进程很忙可以用 signal 注册信号处理函数在信号处理函数调用 wait/waitpid 等待子进程退出。 4.通过两次调用 fork。父进程首先调用 fork 创建一个子进程然后 waitpid 等待子进程退出 子进程再 fork 一个孙进程后退出。这样子进程退出后会被父进程等待回收而对于孙子进程其父 进程已经退出所以孙进程成为一个孤儿进程孤儿进程由 init 进程接管孙进程结束后init 会等待回收。 第一种方法忽略 SIGCHLD 信号这常用于并发服务器的性能的一个技巧因为并发服务器常常 fork 很多子进程子进程终结之后需要服务器进程去 wait 清理资源。如果将此信号的处理方式 设为忽略可让内核把僵尸子进程转交给 init 进程去处理省去了大量僵尸进程占用系统资源。
4、僵尸进程的处理方法
4.1 wait连接
#include sys/types.h
#include sys/wait.h
pid_t wait(int *status);
进程一旦调用了 wait就立即阻塞自己由 wait 自动分析是否当前进程的某个子进程已经退出如果让它找 到了这样一个已经变成僵尸的子进程wait 就会收集这个子进程的信息并把它彻底销毁后返回如果没有找 到这样一个子进程wait 就会一直阻塞在这里直到有一个出现为止。 参数 status 用来保存被收集进程退出时的一些状态它是一个指向 int 类型的指针。但如果我们对这个子进程 是如何死掉的毫不在意只想把这个僵尸进程消灭掉事实上绝大多数情况下我们都会这样想我们就可 以设定这个参数为 NULL就象下面这样
pid wait(NULL);
如果成功wait 会返回被收集的子进程的进程 ID如果调用进程没有子进程调用就会失败此时 wait 返回 -1同时 errno 被置为 ECHILD。 wait 系统调用会使父进程暂停执行直到它的一个子进程结束为止。返回的是子进程的 PID它通常是结束的子进程状态信息允许父进程判定子进程的退出状态即从子进程的 main 函数返回的值或子进程中 exit 语句的退 出码。 如果 status 不是一个空指针状态信息将被写入它指向的位置4.2 waitpid函数 #include #include pid_t waitpid(pid_t pid, int *status, int options); 参数:
status:如果不是空会把状态信息写到它指向的位置与 wait 一样
options允许改变 waitpid 的行为最有用的一个选项是 WNOHANG,它的作用是防止 waitpid 把调用者的执行挂起
返回值如果成功返回等待子进程的 ID失败返回-1
对于 waitpid 的 pid 参数的解释与其值有关
pid -1 等待任一子进程。于是在这一功能方面 waitpid 与 wait 等效。
pid 0 等待其进程 I D 与 p i d 相等的子进程。
pid 0 等待其组 I D 等于调用进程的组 I D 的任一子进程。换句话说是与调用者进程同在一个组的进程。
pid -1 等待其组 I D 等于 p i d 的绝对值的任一子进程 wait 与 waitpid 区别 在一个子进程终止前 wait 使其调用者阻塞而 waitpid 有一选择项可使调用者不阻塞。 waitpid 并不等待第一个终止的子进程—它有若干个选择项可以控制它所等待的特定进程。 实际上 wait 函数是 waitpid 函数的一个特例。waitpid(-1, status, 0); 示例如下代码会创建100个子进程但是父进程并没有等待他们结束所以在父进程退出前会有100个僵尸进程
#include stdio.h
#include unistd.h
int main() { int i; pid_t pid; for(i0; i100; i) { pid fork(); if(pid 0) break; } if(pid0) { printf(press Enter to exit...); getchar(); } return 0;
}
其中一个解决方法即是编写一个SIGCHLD信号处理程序来调用wait/waitpid来等待子进程返回。
#include stdio.h
#include unistd.h
#include signal.h
#include sys/types.h
#include sys/wait.h
void wait4children(int signo) { int status; wait(status);
} int main() { int i; pid_t pid; signal(SIGCHLD, wait4children); for(i0; i100; i) { pid fork(); if(pid 0) break; } if(pid0) { printf(press Enter to exit...); getchar(); } return 0;
}所以最佳的方案如下
#include stdio.h
#include unistd.h
#include signal.h
#include errno.h
#include sys/types.h
#include sys/wait.h void wait4children(int signo) { int status; pid_t pid;while(pidwaitpid(-1, status, WNOHANG) 0){
//if (WIFEXITED(status))// printf(------------child %d exit %d\n, pid, WEXITSTATUS(status));// else if (WIFSIGNALED(status))// printf(child %d cancel signal %d\n, pid, WTERMSIG(status));
}
} int main() { int i; pid_t pid; signal(SIGCHLD, wait4children); for(i0; i100; i) { pid fork(); if(pid 0) break; } if(pid0) { printf(press Enter to exit...); getchar(); } return 0;
}
这里使用 waitpid 而不是使用 wait 的原因在于我们在一个循环内调用 waitpid以获取 所有已终止子进程的状态。我们必须指定 WNOHANG 选项它告诉 waitpid 在有尚未终止的子进程 在运行时不要阻塞。我们不能在循环内调用 wait因为没有办法防止 wait 在正运行的子进程尚 有未终止时阻塞。