Linux学习总结(九)回收子进程

孤儿进程

父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程称为init进程,称为init进程领养孤儿进程。

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

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

    if (pid == 0) {
    
    
        while (1) {
    
    
            printf("I am child, my parent pid = %d\n", getppid());
            sleep(1);
        }
    } else if (pid > 0) {
    
    
            printf("I am parent, my pid is = %d\n", getpid());
            sleep(9);
            printf("------------parent going to die------------\n");
    } else {
    
    
        perror("fork");
        return 1;
    }

    return 0;
}

僵尸进程

进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。
特别注意:僵尸进程是不能使用kill命令清除掉得,因为kill命令只是用来中止进程的,而僵尸进程已经终止。

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

int main(void)
{
    
    
    pid_t pid, wpid;
    pid = fork();

    if (pid == 0) {
    
    
            printf("---child, my parent= %d, going to sleep 10s\n", getppid());
            sleep(10);
            printf("-------------child die--------------\n");
    } else if (pid > 0) {
    
    
        while (1) {
    
    
            printf("I am parent, pid = %d, myson = %d\n", getpid(), pid);
            sleep(1);
        }
    } else {
    
    
        perror("fork");
        return 1;
    }

    return 0;
}

wait函数

一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是那个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在Shell中用特殊变量$?查看,因为Shell是它的父进程,当它终止时Shell调用wait或waitpid得到它的退出状态同时彻底清除掉这个进程。
父进程调用wait函数可以回收子进程终止信息。该函数有三个功能:

  • 阻塞等待子进程退出
  • 回收子进程残留资源
  • 获取子进程结束状态(退出原因)

pid_t wait(int *status)
成功:返回清理掉的子进程ID;
失败:返回-1(没有子进程)

当进程终止时,操作系统的隐式回收机制会:

  • 关闭所有文件描述符
  • 释放用户空间分配的内存。内核的PCB仍存在,其中保存该进程的退出状态。(正常终止→退出值;异常终止→终止信号)

可使用wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步判断进程终止的具体原因。宏函数可氛围如下三组:

  1. WIFEXITED(status) 为非0 → 进程正常结束
    WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)
  2. WIFSIGNALED(status) 为非0 → 进程异常终止
    WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。
  3. WIFSTOPPED(status) 为非0 → 进程处于暂停状态
    WSTOPSIG(status) 如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。
    WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

int main(void)
{
    
    
	pid_t pid, wpid;
	int status;

	pid = fork();

	if(pid == -1)
	{
    
    
		perror("fork error");
		exit(1);
	} 
	else if(pid == 0)
	{
    
    		//son
		printf("I'm process child, pid = %d\n", getpid());
#if 1
		execl("./abnor", "abnor", NULL);
		perror("execl error");
		exit(1);
#endif
		sleep(1);				
		exit(10);
	} 
	else 
	{
    
    
		//wpid = wait(NULL);	//传出参数
		wpid = wait(&status);	//传出参数

		if(WIFEXITED(status)){
    
    	//正常退出
			printf("I'm parent, The child process "
					"%d exit normally\n", wpid);
			printf("return value:%d\n", WEXITSTATUS(status));

		} 
		else if (WIFSIGNALED(status)) 
		{
    
    	//异常退出
			printf("The child process exit abnormally, "
					"killed by signal %d\n", WTERMSIG(status));
										//获取信号编号
		}
		else 
		{
    
    
			printf("other...\n");
		}
	}
	return 0;
}

waitpid函数

作用同wait,但可以指定pid进程清理,可以不阻塞。

pid_t waitpid(pid_t pid, int *status, int options);
成功:返回清理掉的子进程ID;
失败:返回-1(无子进程)

特殊参数和返回情况:
参数pid:

  • >0 回收指定ID的子进程
  • -1 回收任意子进程(相当于wait)
  • 0 回收和当前调用waitpid一个组的所有子进程
  • <-1 回收指定进程组内的任意子进程

返回0且第三个参数为WNOHANG,表示子进程正在运行。
注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。

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

int main(void)
{
    
    
	pid_t pid, pid2, wpid;
	int flg = 0;

	pid = fork();
	pid2 = fork();

	if(pid == -1)
	{
    
    
		perror("fork error");
		exit(1);
	} 
	else if(pid == 0)
	{
    
    		//son
		printf("I'm process child, pid = %d\n", getpid());
		sleep(5);				
		exit(4);
	} 
	else 
	{
    
    					//parent
		do 
		{
    
    
			wpid = waitpid(pid, NULL, WNOHANG);
            //wpid = wait(NULL);
			printf("---wpid = %d--------%d\n", wpid, flg++);
			if(wpid == 0)
			{
    
    
				printf("NO child exited\n");
				sleep(1);		
			}
		} while (wpid == 0);		//子进程不可回收

		if(wpid == pid)
		{
    
    		//回收了指定子进程
			printf("I'm parent, I catched child process,"
					"pid = %d\n", wpid);
		} 
		else 
		{
    
    
			printf("other...\n");
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/bureau123/article/details/112064406