孤儿进程
孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程。子进程的父进程变成init进程。init-->1号进程,被称为进程孤儿院。【孤儿进程是没有危害的】
init进程会循环的wait()它的已经退出的子进程。这样,当一个子进程凄凉的结束了其生命的时候,init进程就会代表党和政府出面处理它的一切善后工作,因此,孤儿进程并不会有什么危害。
僵尸进程
僵尸进程:进程终止,父进程尚未回收(父进程后于子进程结束)。子进程残留的资源(PCB)存放在内核中,变成了僵尸进程。僵尸进程危害很大,应尽量避免。
- 每个进程结束之后,都会释放自己地址空间中的用户区数据,内核区的PCB没有办法自己释放掉,需要父进程去释放。(父进程的父进程是当前所在的bash,或者说终端)
- 进程终止时,父进程尚未回收子进程残留的资源(PCB)存在于内核中,变成了僵尸进程。
- 僵尸进程不能被 kill -9 杀死,因为已经终止了,不可能接收信号。
- 这样会导致一个很严重的问题,如果父进程不调用wait()或waitpid()的话,那么保留的那段信息就不会释放,其进程号就会被一直占用(进程号存在内核区中的PCB中),但是进程号能使用的进程号是有限的(pid_t 也是无符号整型而已),如果大量的僵尸进程产生,将因为没有可用的进程号而导致系统不能产生新的进程。
- 解决僵尸进程的方法:1).杀死其父进程 【这种方式显然不合理,父进程的工作没有做完就杀死,芭比Q了】 2).在父进程中调用wait() waitpid()回收子进程残留的资源。
进程回收
- 在每个进程退出的时候,内核释放该进程的几乎所有的资源,用户区的所有资源。包括打开的文件、占用的内存等。但仍然为其保留一定的信息,这些信息主要指进程控制块PCB的信息(进程号、进程退出状态)。
- 父进程可以通过调用wait()或者waitpid()得到它的退出状态,同时彻底清除掉这个进程。
- wait()和waitpid()函数的功能一样,区别在于wait()函数会阻塞。 waitpid()可以设置非阻塞,waitpid()还可以指定等待哪个子进程结束。
- 一次wait()和waitpid()调用只能清理一个子进程,清理多个子进程需要使用循环。
- wait()和waitpid()采用轮询的方式。
pid_t wait(int * wstatus);
-功能:等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收子进程残留的资源。
-参数:wstatus 进程退出时的状态信息,传入的是一个int类型的地址 【传出参数】
-返回值:成功 返回被回收的子进程的id
失败 -1(所有的子进程都结束了,函数调用失败)
-说明:调用wait函数的进程会被挂起(阻塞),直到它的一个子进程退出或者收到一个不能忽略的信号时才被唤醒,才继续往下执行。
pid_t waitpid(pid_t pid,int wstatus,int options);
-功能:回收子进程残留的资源。
-参数:wstatus 进程退出时的状态信息,传入的是一个int类型的地址 【传出参数】
pid:
>0 回收指定ID的子进程
-1 回收任意子进程(相当于wait)
0 回收和当前调用waitpid一个组的所有子进程
<-1 回收指定进程组内的任意子进程(取绝对值)
options:指定是否阻塞
0 阻塞
WNOHANG 不阻塞
-返回值:成功 返回被回收的子进程的id
失败 -1(指定的所有的子进程都结束了,函数调用失败)
WSTATUS:
WIFEXITED(status) 为非0 --->程序正常退出
WEXITSTATUS(status):获取进程退出状态
WIFSIGNALED(status) 为非0 --->程序异常退出
WTERMSIG(status):取得使进程退出那个信号
WIFSTOPPED(status) 为非0 -->程序处于暂停状态
WSTOPSIG(status):取得使进程暂停那个信号
WIFCONTINUED(status):进程退出后已继续运行。
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> int main(){ //创建子进程 pid_t pid = fork(); if(pid == -1){ perror("fork"); return 0; } if(pid > 0){ //父进程 int status; pid_t wpid = wait(&status); if(WIFEXITED(status)){ printf("status %d\n",WEXITSTATUS(status)); }else if(WIFSIGNALED(status)){ printf("status %d\n",WTERMSIG(status)); } }else if(pid == 0){ printf("child child childXXXXXXXXXXX\n"); sleep(2); while(1){ } } return 0; }
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> int main(){ //创建子进程 pid_t pid = fork(); if(pid == -1){ perror("fork"); return 0; } if(pid > 0){ //父进程 int status; pid_t wpid = waitpid(-1,&status,WNOHANG); if(WIFEXITED(status)){ printf("status %d\n",WEXITSTATUS(status)); }else if(WIFSIGNALED(status)){ printf("status %d\n",WTERMSIG(status)); } }else if(pid == 0){ printf("child child childXXXXXXXXXXX\n"); sleep(2); while (1) { /* code */ } } return 0; }