目录
- 进程退出
- 孤儿进程
- 僵尸进程
- wait函数
- waitpid函数
进程退出
exit 刷新IO缓冲区
_exit
孤儿进程
父进程运行结束,但子进程还在运行,这样的子进程称为孤儿进程。
每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。init进程会在孤儿进程结束后处理它的善后工作,因此孤儿进程并不会有什么危害
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(){
//创建子进程
pid_t pid=fork();
//判断,判断是父进程还是子进程
if(pid>0){
//如果大于0,返回的是创建的子进程的进程号,当前是父进程
printf("i am parent process,pid :%d,ppid:%d\n",getpid(),getppid());
}else if(pid==0){
sleep(1);
//当前是子进程
printf("i am child process,pid:%d,ppid:%d\n",getpid(),getppid());
}
//for循环
for(int i=0;i<3;i++){
printf("i:%d,pid:%d\n",i,getpid());
}
return 0;
}
子进程的父进程的Id变成了1,孤儿进程的父进程会给进程号为1 的Init
那为什么又出现终端信息了呢?
因为父进程结束之后,切换到前台,然后子进程还有输出,继续输出出来,
僵尸进程
相对于无害的孤儿进程,僵尸进程比较麻烦和可怕
每个进程结束之后,都会释放自己地址空间中的用户区数据,内核区的PCB没有办法自己释放掉,需要父进程去释放。
进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸进程
僵尸进程不能被kill -9杀死
这样就会导致一个问题,如果父进程不调用wait()或waitpid()的话,那么保留的那段信息就不会释放,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免
因此父进程必须去释放子进程的资源。
僵尸进程是子进程都死了,父进程没有去回收资源
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(){
//创建子进程
pid_t pid=fork();
//判断,判断是父进程还是子进程
if(pid>0){
while(1){
//如果大于0,返回的是创建的子进程的进程号,当前是父进程
printf("i am parent process,pid :%d,ppid:%d\n",getpid(),getppid());
sleep(1);
}
}else if(pid==0){
//当前是子进程
printf("i am child process,pid:%d,ppid:%d\n",getpid(),getppid());
}
//for循环
for(int i=0;i<3;i++){
printf("i:%d,pid:%d\n",i,getpid());
}
return 0;
}
Z+的状态就是僵尸进程,仍占据一个进程号,然而进程号是有限的
僵尸进程无法被kill -9 进程号杀死,因为他不是一个正常的进程
父进程用ctrl+c结束,杀死
而在正式的开发中,无法这样结束父进程,一般调用wait()和waitpid()函数来结束
wait函数
父进程通过wait得到它的退出状态同时彻底清除掉这个进程
等待子进程结束之后,回收它的资源
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
//有一个父进程,创建5个子进程(兄弟)
pid_t pid;
for(int i=0;i<5;i++){
pid=fork();
if(pid==0){
break;
}
}
if(pid>0){
//父进程
while(1){
printf("parent,pid=%d\n",getpid());
int st;
int ret =wait(&st);
if(ret==-1){
break;
}
if(WIFEXITED(st)){
//是不是正常退出
printf("退出的状态码:%d\n",WEXITSTATUS(st));
}
if(WIFSIGNALED(st)){
//是不是异常终止
printf("被那个信号干掉了:%d\n",WTERMSIG(st));
}
printf("child die,pid=%d\n",ret);
sleep(1);
}
}else if(pid==0){
//子进程
// while(1){
printf("child,pid=%d\n",getpid());
sleep(1);
//}
exit(0);
}
return 0;
}
目前有5个僵尸进程
wait函数就是会阻塞在那,如果有一个进程被回收了,会运行一次,然后继续运行。
waitpid函数
阻塞就是在等待某些条件触发之后再运行
使用了waitpid之后,即使子进程未执行完,父进程仍可以执行自己的业务逻辑,但是wait的话,父进程就会暂停等到子进程回收之后再继续运行一次。
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
//有一个父进程,创建5个子进程(兄弟)
pid_t pid;
for(int i=0;i<5;i++){
pid=fork();
if(pid==0){
break;
}
}
if(pid>0){
//父进程
while(1){
printf("parent,pid=%d\n",getpid());
sleep(1);
int st;
int ret =waitpid(-1,&st,WNOHANG);
if(ret==-1){
break;
}
if(ret==0){
//说明还有子进程存在
continue;
}else if(ret>0){
if(WIFEXITED(st)){
//是不是正常退出
printf("退出的状态码:%d\n",WEXITSTATUS(st));
}
if(WIFSIGNALED(st)){
//是不是异常终止
printf("被那个信号干掉了:%d\n",WTERMSIG(st));
}
printf("child die,pid=%d\n",ret);
}
}
}else if(pid==0){
//子进程
while(1){
printf("child,pid=%d\n",getpid());
sleep(1);
}
exit(0);
}
return 0;
}