← 返回首页
Linux高级程序设计(三十二)
发表时间:2021-11-19 16:52:13
进程清理和特殊进程

atexit函数是一个特殊的函数,它是在正常程序退出时调用的函数,我们把他叫为登记函数。

1.进程清理 函数原型:

#include <stdlib.h>
int atexit (void (*)(void));

exit调用这些注册函数的顺序与它们登记时候的顺序相反。同一个函数如若登记多次,则也会被调用多次。

实例:

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

void clearfun1(void){
    printf("clearfun1\n");
}

void clearfun2(void){
    printf("clearfun2\n");
}

void clearfun3(void){
    printf("clearfun3\n");
}

int main(int argc, char* argv[]){

    atexit(clearfun1);
    atexit(clearfun2);
    atexit(clearfun3);
    printf("the program will be end in 3 senconds...\n");
    sleep(3);

    return 0;
}

运行结果:

[root@iz2zefozq9h39txdb8s7npz shelldemo]# ./a.out
the program will be end in 3 senconds...
clearfun3
clearfun2
clearfun1

2.特殊进程

  1. 僵尸进程(Zombie Process):进程已运行结束,但进程的占用的资源未被回收,这样的进程称为僵尸进程。在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。 但是仍然为其保留一定的信息,这些信息主要主要指进程控制块的信息(包括进程号、退出状态、运行时间等)。直到父进程通过 wait() 或 waitpid() 来获取其状态并释放(具体用法,请看《等待进程结束》)。 这样就会导致一个问题,如果进程不调用wait() 或 waitpid() 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程.此即为僵尸进程的危害,应当避免。子进程已运行结束,父进程未调用 wait() 或 waitpid() 函数回收子进程的资源是子进程变为僵尸进程的原因。

  2. 孤儿进程(Orphan Process):父进程运行结束,但子进程还在运行(未运行结束)的子进程。孤儿进程最终会被 init 进程(进程号为1)所收养,并由 init 进程对它们完成状态收集工作。孤儿进程是没有父进程的进程,为避免孤儿进程退出时无法释放所占用的资源而变为僵尸进程,进程号为 1 的 init 进程将会接受这些孤儿进程,这一过程也被称为“收养”。init 进程就好像是一个孤儿院,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为 init ,而 init 进程会循环地 wait() 它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init 进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

  3. 守护进程(Daemon Process):Daemon 进程(精灵进程),是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。Linux 的大多数服务器就是用守护进程实现的。比如,Internet 服务器 inetd,Web 服务器 httpd 等。

如何查看守护进程?

在终端输入:ps axj - a 表示不仅列当前用户的进程,也列出所有其他用户的进程 - x 表示不仅列有控制终端的进程,也列出所有无控制终端的进程 - j 表示列出与作业控制相关的信息

从上图可以看出守护进行的一些特点:

一般情况下,守护进程可以通过以下方式启动: