Linux操作系统-进程-回收子进程

150 阅读4分钟

基本概念

查看进程的命令

ps -ajx

孤儿进程

父进程领先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为init进程领养孤儿进程,mac的init进程的pid=1

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>

int main(){
	pid_t pid;
	pid = fork();
	
	if(pid==0){ //让子进程一直活着
		while(1){
			printf("I am child process, my parent pid = %d\n",getppid());
			sleep(2);
		}
	}else if(pid>0){ //让父进程活一会儿
		printf("I am parent process, my pid = %d\n",getpid());
		sleep(9);
	}else if(pid<0){
		perror("create child process error");
		exit(1);
	}
	
}

僵尸进程

子进程先于父进程死亡。进程终止,父进程尚未回收该进程,子进程残留资源(PCB)存放于内核中,变成僵尸进程。就是没人收尸,叫僵尸。所有进程肯定都会经历,不可能你一结束,你的父进程就能回收你。

  • 僵尸进程不能用kill,kill是用来终止进程的,但是人家本来就已经终止了,只是资源没有回收,你kill就没用,要用wait主动回收
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>

int main(){
	pid_t pid;
	pid = fork();
	
	if(pid==0){ //让子进程死		
		printf("I am child process, my parent pid = %d\n",getppid());
		sleep(9);
		printf("child process die\n");
	}else if(pid>0){ //让父进程活着
		while(1){
			printf("I am parent process, my pid = %d, my child pid = %d\n",getpid(),pid);
			sleep(2);
		}
	}else if(pid<0){
		perror("create child process error");
		exit(1);
	}
	
}

查询死亡后的子进程号,显示defunct失去功能,即僵尸进程

image.png

wait函数

pid_t wait(int* status);

返回值:

  • 成功:回收的子进程pid
  • 失败:-1,设置errono

传出参数:

  • status:关于子进程终止的一些情况

函数作用:

  1. 阻塞等待子进程退出
  2. 清理子进程残留在内核的pcb
  3. 通过传出参数,得到子进程结束状态

status作用:

  1. 获取子进程正常终止值:
  • WIFEXITED(status) -> 为真 -> WEXITSTATUS(status) -> 得到子进程退出值
  1. 获取导致子进程异常终止的信号:
  • WIFSIGNALED(status) -> 为真 -> WTERMSIG(staus) -> 得到导致子进程一场终止的信号值

如果你不需要使用传出参数:

  • pid_t pid=wait(NULL);
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>

int main(){
	pid_t pid;  
	pid = fork();

	int status;
	
	if(pid==0){ 		
		printf("I am child process,my pid=%d, my parent pid = %d\n",getpid(),getppid());
		sleep(9);
		printf("child process die\n");
		return 74; //status可以监测到返回值
	}else if(pid>0){ 
		pid_t wpid = wait(&status); //会阻塞等待子进程死亡
		if(wpid==-1){
			perror("wait error");
			exit(1);
		}

		//wpid返回的是被回收的子进程的pid,status存放关于子进程终止的信息
		if(WIFEXITED(status)){ //为真,表示子进程正常终止,exit和return都算
			printf("child exit with %d\n",WEXITSTATUS(status)); //返回正常终止时的返回值
		}
		if(WIFSIGNALED(status)){  //为真,表示子进程被信号终止,kill命令之类的
			printf("child kill with signal %d\n",WTERMSIG(status)); //返回终止进程的信号
		}
		
	}else if(pid<0){
		perror("create child process error");
		exit(1);
	}
	
}

waitpid

pid_t waitpid(pid_t pid, int *status, int option)

返回值:

  • >0:成功回收的子进程pid
  • 0:函数调用时,子进程还没结束,而且option指定了WNOHANG,即不阻塞状态下没回收到东西
  • -1:失败,设置errno

参数:

  • pid:指定回收的子进程pid
  1. >0:成功回收的子进程pid
  2. -1:任意子进程
  3. 0:同组子进程
  • status:关于子进程终止的一些情况
  • option:可以设置非阻塞,WNOHANG,wait not hang,不挂起
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>

int main(int argc, char* argv[]){
    int i;
    pid_t pid,wpid,pid_2;

    for(int i=0;i<5;i++){
        pid=fork();
        if(pid==-1){
            perror("fork error");
            exit(1);
        }
        if(pid==0){   //如果当前是子进程就退出
            printf("I am the %dth child, my pid is %d\n",i,getpid());
            sleep(i);
            exit(1);
        }
        if(i==2){ //记录第三个子进程的pid
            pid_2=pid;
        }        
    }
    sleep(5);
    wpid = waitpid(pid_2,NULL,WNOHANG); //回收第二个子进程,不阻塞
    //wpid = waitpid(-1,NULL,WNOHANG); //回收任意子进程,不阻塞
    //wpid = waitpid(-1,NULL,0); //回收任意子进程,因为WNOHANG是宏,你随便填一个其他的就阻塞了
    printf("I am parent, wait a child finish: %d \n",wpid);
}

wait和waitpid注意

一次调用就只回收一个子进程,只有waitpid可以指定回收
wait(&status) = waitpid(-1,&status,0)

回收多个子进程

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>

int main(int argc, char* argv[]){
    int i;
    pid_t pid,wpid,pid_2;

    for(int i=0;i<5;i++){
        pid=fork();
        if(pid==-1){
            perror("fork error");
            exit(1);
        }
        if(pid==0){
            printf("I am the %dth child, my pid is %d\n",i,getpid());
            exit(1);
        }
        wpid = waitpid(pid,NULL,0);  //没回收子进程,就阻塞,不会进入下一次创建
        printf("I am parent, wait a child finish: %d \n",wpid);
    }
}