wait、waitpid

本文详细介绍了孤儿进程和僵尸进程的概念,以及如何通过wait和waitpid函数来管理和回收这些进程。示例代码展示了孤儿进程、僵尸进程的创建,以及wait和waitpid的使用,解释了它们在进程生命周期中的作用。
摘要由CSDN通过智能技术生成

一、孤儿进程

 父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程变成init进程,负责子进程的回收。


示例:

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

int main(void)
{
        pid_t pid = fork();
        if(pid > 0){         // 父进程输出pid并睡眠2s退出
                printf("parent pid is %d\n", getpid());
                sleep(2);
        }
        else if(pid == 0){   // 子进程循环打印pid和ppid
                for(int i=0;i<10;i++){
                        printf("my pid is %d, my ppid is %d\n", getpid(), getppid());
                        sleep(1);
                }
        }
        else {
                perror("fork");
                exit(1);
        }
        return 0;
}


运行结果:

在这里插入图片描述


二、僵尸进程

 僵尸进程:进程终止,父进程没有回收,子进程残留的PCB存放在内核中,变成僵尸(zombie)进程。

 僵尸进程无法用kill杀掉,因为kill只是用来终止进程的,僵尸进程已经终止。正确方法是kill掉它的父进程,如此僵尸进程就会被init进程管理回收。


示例:

/*
    我们让父进程一直循环,子进程打印出pid和ppid后就退出
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(void)
{
	pid_t pid = fork();
	if(pid > 0){
		while(1){
			printf("parent pid is %d\n", getpid());
			sleep(2);
		}
	}
	else if(pid == 0){
		printf("my pid is %d, my parent pid is %d\n", getpid(), getppid());
		sleep(1);
	}
	else {
		perror("fork");
		exit(1);
	}
	return 0;
}

结果:

在这里插入图片描述


三、wait

​  一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着。内核在其中保存了一些信息:
​     如果是正常终止则保存着退出状态;
​     如果是异常终止则保存着导致该进程终止的信号是哪个。

​  这个进程的父进程可以调用waitwaitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在Shell中用特殊变量$?查看,因为Shell是它的父进程,当它终止时Shell调用waitwaitpid得到它的退出状态,同时彻底删除掉这个进程。


wait()的作用:

1、阻塞等待子进程结束。

2、回收子进程pcb资源。

3、获取子进程结束状态:

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);

//	return
//	on success, returns the process ID of the terminated child; 
//	on error, -1 is returned.

// status 子进程退出时返回的状态,通过下面的宏函数检查状态信息。
//	WIFEXITED(status)	为真 ->	子进程正常退出。
//		WEXITSTATUS(status)	当子进程正常退出时,通过此函数获取退出值。
//	WIFSIGNALED(status)	为真 ->	子进程异常退出,被信号终止。
//		WTERMSIG(status)	当子进程异常退出时,通过此函数获取退出时收到的信号。

//	其它的宏函数:
//	WCOREDUMP(status)
//	WIFSTOPPED(status)
//		WSTOPSIG(status)
//	WIFCONTINUED(status)


示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

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

        if (pid == 0)
        {
                printf("I am the child process, pid=%u, ppid=%u\n", getpid(), getppid());
                sleep(2);
                execl("./test", "test", NULL);
        }
        else if (pid > 0)
        {
                int status;
                pid_t wpid;
                wpid = wait(&status);
                if (wpid == -1)
                {
                        perror("wait error");
                        exit(-1);
                }
                if (WIFEXITED(status))
                {
                        printf("child exit with %d.\n",WEXITSTATUS(status));
                }
                if (WIFSIGNALED(status))
                {
                        printf("child exit with signal:%d \n", WTERMSIG(status));
                }

                printf("I am the parent process, pid=%u\n", getpid());
        }
        else
        {
                perror("fork error");
                exit(-1);
        }

        return 0;
}

test.c

#include <stdio.h>

int main()
{
        int a = 5;
        int b = a/0;

        return 25;
}

输出结果:

I am the child process, pid=19092, ppid=19091
child exit with signal:8 
I am the parent process, pid=19091

test.c:正常结束

 #include <stdio.h>
 
 int main()
 {
     int a = 5;
     int b = a/1;
 
     return 25;
 }

输出结果:

I am the child process, pid=19903, ppid=19902
child exit with 25.
I am the parent process, pid=19902

Note:

一次wait()、waitpid()调用,只回收一个子进程。


四、waitpid

 作用与wait相同,但可指定pid进程清理,可以不阻塞等待子进程结束(采用轮询方式检查子进程是否结束)。

#include <sys/types.h>
#include <sys/wait.h>

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

//	参数1: pid > 0 指定进程id回收
/*
pid > 0  指定进程id回收
pid = -1 回收任意子进程 (==wait)
pid = 0  回收本组任意子进程
pid < -1 回收该进程组的任意子进程,如-2,就回收所有进程组为2的任意子进程。
*/

//	参数2:status 同 wait()

//	参数3:options
//	0:  阻塞回收,同wait()
//	WNOHANG: 非阻塞回收(轮询回收)

//	返回值:
//	成功: pid 
//	失败: -1
//	参3传WNOHANG,并且子进程尚未结束: 0


示例:创建5个子进程,并回收

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


int main()
{
        pid_t pid, wpid;
        int n = 5;
        int i;

        for (i=0; i < n; i++)
        {
                //      创建n个子进程
                pid = fork();
                if (pid == 0)
                {
                        break;
                }
        }

        if (n == i)
        {
                //      父进程
                do {
                        wpid = waitpid(-1, NULL, WNOHANG);
                        if (wpid > 0)
                        {
                                n--;
                                printf("recycle child process:%u\n", wpid);
                        }
                        sleep(1);
                } while(n > 0);

                while(1)
                {
                        printf("I am the parent process, pid:%u\n", getpid());
                        sleep(1);
                }
        }
        else
        {
                //      子进程等待一段时间
                printf("I am the %dth child process, pid=%u, ppid=%u\n", getpid(), getppid());
                sleep(i);
        }

        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值