孤儿进程与僵尸进程

孤儿进程:

父进程先死了,子进程被init进程领养,即子进程的父进程pid变成了1

这个子进程就叫孤儿进程

僵尸进程:

子进程死了,但是父进程没有回收子进程的资源(子进程的资源必须由父进程回收,操作系统不会自动回收)

任何进程都会存在僵尸进程阶段,只不过有些及时被回收了

因为僵尸进程是已经死掉的进程,因此用kill没办法回收僵尸进程

子进程回收

一个进程终止时关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留的,内核在其中保留一些信息:

如果是正常终止,则保留着退出状态

如果是异常终止,则保存导致该进程终止的信号是哪个

终止进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程

wait函数

作用:

1 阻塞等待,即在父进程中调用的wait会一直等待子进程死亡然后再进行回收

2 回收子进程资源

3 查看死亡原因

pid_t wait(int *status)

status: 是一个传出参数,即定义一个整型变量,然后把该整型变量传进wait函数中就行,然后操作系统会给该形参复制,从而获取进程的结束状态

返回值:如果成功,返回已经终止的子进程的pid,如果失败返回-1

 

int main(){
	pid_t pid = fork();
    if(pid == 0){
        cout<<"孩子"<<endl;
        sleep(2);    
    }
    else if(pid > 0){
    	cout<<"父进程"<<endl;
        int status; // 整型数,用来接收子进程终止状态
        pid_t wpid = wait(&status); // 如果子进程不死,则父进程会停留再这一行语句阻塞等待,如果不看终止状态的话,直接传入NULL就行,不用特地传个整型数
        
        if(WIFEXITED(status)){
        	cout<<"退出状态"<<WEXITEDSTATUS(status)<<endl;
        }
        if(WIFSIGNALED(status)){
        	cout<<"孩子被几号信号杀死?"<<WTERMSIG(status)<<endl;
        }
        cout<<"孩子die"<<endl;
        while(1){
			sleep(1);        
        }
    }
    return 0;
}

子进程死亡原因可以把status传入几个宏来获取

正常死亡:WIFEXITED(status) == true, 代表正常死亡,WEXITSTATUS(status)得到退出状态(退出状态一般指的是子进程的返回值,比如return 101, 那就是101,exit(544),那就是544)

非正常死亡:WIFSIGNALED(status) == true, 代表非正常死亡,WTERMSIG得到是第几号信号将其杀死的

 

waitpid函数

pid_t waitpid(pie_t pid, int *status, int options)

返回值:

成功:返回清理掉的子进程ID

失败:-1(当当前进程没有子进程的时候,回收失败)

如果设置了WNOHANG,那么会返回0

参数pid:

>0 回收指定ID的子进程

-1 回收任意子进程

0 回收进程组ID与当前父进程的进程组ID相同的子进程,这说明了一个问题,虽然一般情况下子进程的进程组ID等于父进程的进程组ID,但是子进程的进程组ID也是可以不等于其父进程的进程组ID的,这种情况下就不能用pid=0来回收该进程了,所以还是用pid=-1比较好

-1 回收指定进程组内的任何子进程,这个进程组的组ID就是pid的绝对值,这意味着有多个子进程其组ID相同,但是与父进程的组ID不同,但血浓于水,父进程还是要回收他们

options:

可以为0或者WNOHANG

0: 跟wait一样,waitpid会发生阻塞等待

WNOHANG: 如果没有子进程退出,会立刻返回

回收多个子进程

 

wait和waitpid一次都是只能回收一个子进程,如果要回收多个子进程,可能就要用一个循环依次回收了

现在给出waitpid回收逻辑

if(i == 5){
    // 父进程的逻辑
    while(1){
        pid_t wpid = waitpid(-1, NULL, WNOHANG);
        if(wpid == -1){
        	// 说明已经没有子进程
            break;
        }
        else if(wpid > 0){
        	cout<<"回收子进程ID"<<wpid<<endl;
        }
    
    }


}

 

 

上一篇:MJ李明杰带你深入探索iOS底层原理


下一篇:C语言父子进程,waitpid的使用