添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

1. 僵尸进程与孤儿进程

孤儿进程:父进程结束,子进程被init进程收养。

僵尸进程:子进程结束,父进程没有回收子进程的资源(PCB),这个资源必须要由父进程回收,否则就形成僵尸进程。

测试1: 孤儿进程测试

image

我们看到,子进程的父进程ID在3秒后变成了1,这说明父进程结束后,它变成了孤儿进程,并被init进程收养,使用 kill命令 基于可以杀死孤儿进程。

测试2: 僵尸进程测试

/************************************************************
  >File Name  : zombie.c
  >Author     : Mindtechnist
  >Company    : Mindtechnist
  >Create Time: 2022年05月19日 星期四 20时54分20秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
    pid_t pid = fork();
    if(pid == 0)
        printf("child: %d, ppid: %d\n", getpid(), getppid());   
        sleep(1);
    if(pid > 0)
        while(1)
            printf("parent: %d\n", getpid());   
            sleep(1);
    return 0;
}

我们可以通过ps命令查看僵尸进程

image

图中红色标出的三个地方Z+、[]、default都可以表明这是僵尸进程,另外Z+是进程类型的一个表示,可以通过 man ps 查看,我们可以通过 man ps 进入帮助手册,然后在命令行输入 /zombie 来搜索zombie相关的信息。

image

僵尸进程是不能用kill杀死的,因为kill命令是终止进程,而僵尸进程已经终止了。我们知道僵尸进程的资源需要由父进程去回收,那么我们在这种情况下如何回收僵尸进程的资源呢?方法就是杀死父进程,父进程被杀死后,由init接管子进程并回收子进程资源。

image

2. wait()函数与 waitpid ()函数

2.1 wait()函数

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

案例测试: wait()获取子进程退出原因

我们首先演示一下子进程的正常退出,并获取退出状态,子进程的退出状态可以用return或者exit来传递。

image

下面我们在子进程中增加一个循环,然后用信号杀死子进程

重新编译运行,并开启另一个shell,使用 kill -9 杀死子进程

image

获取到杀死进程的信号,正好是9号信号,如果直接使用 kill pid 默认使用的是15号信号。

image

2.2 waitpid()函数

下面通过例子演示waitpid()函数的用法。

image

为什么使用了waitpid()函数还会产生僵尸进程呢,这是因为在waitpid()函数中使用了选项参数WNOHANG,而子进程中有一个睡眠函数,子进程睡眠的时候,父进程中waitpid()语句没有等到子进程结束就执行了,由于WNOHANG选项参数的存在,waitpid不会阻塞等待之进程结束,而是直接返回。当waitpid()返回父进程中后,子进程才结束,但是waitpid()已经执行完了,所以并没有回收子进程,子进程因此变成僵尸进程。

解决方法就是在一个循环中执行waitpid()函数,直到ret不等于0的时候说明子进程退出了,跳出循环。

3. 回收多个子进程

上面使用wait()函数和waitpid()函数举的例子都是回收一个子进程,有时候我们可能需要回收多个子进程,下面介绍回收多个子进程的方法。

3.1 使用wait()回收多个子进程

首先使用wait()函数来回收多个子进程,我们可以在一个for循环中等待子进程的结束,创建了几个子进程就for循环等待几次,代码如下。

编译运行,可以看到所有子进程都被回收。

image

3.2 使用waitpid()回收多个子进程

如果使用waitpid()函数,可以借助函数的参数和返回值去判断每个子进程是否回收成功。

编译执行,可以看到所有进程都被回收了

image

php常用自建函数学习(3):格林威治标准时间、格式化(Y-m-d H:i:s)的时间、Linux时间截转换
php常用自建函数学习(3):格林威治标准时间、格式化(Y-m-d H:i:s)的时间、Linux时间截转换
Linux系统应用编程 --- 信号处理函数(sigprocmask、sigpending函数)
Linux系统应用编程 --- 信号处理函数(sigprocmask、sigpending函数)
【Linux】Linux进程控制 --- 进程创建、终止、等待、替换、shell派生子进程的理解…
【Linux】Linux进程控制 --- 进程创建、终止、等待、替换、shell派生子进程的理解…
【Linux】Linux环境变量的理解 --- 命令行参数、shell子进程、环境变量、本地变量…
【Linux】Linux环境变量的理解 --- 命令行参数、shell子进程、环境变量、本地变量…
Linux——进程控制2|进程程序替换|替换原理|替换函数|替换函数创建子进程|其余替换函数介绍|使用替换致函执行其它文件程序|使用替换致函执行其它语言文件|execlp |下 Linux——进程控制2|进程程序替换|替换原理|替换函数|替换函数创建子进程|其余替换函数介绍|使用替换致函执行其它文件程序|使用替换致函执行其它语言文件|execlp |上