回收进程用户空间资源 exit()函数 _exit()函数 atexit()函数 on_exit()函数

摘要:本文主要讲述进程的终止方式,以及怎样使用exit()函数来终止进程。回收进程用户空间资源;分析了exit()函数与_exit()函数,returnkeyword的差异.同一时候具体解读了怎样使用atexit()和on_exit()函数来注冊终止处理程序.

进程终止、回收资源

1.进程终止方式

    在内核中,程序运行的唯一方法是调用一个exec函数.而进程自愿终止的唯一方法是显示或隐式地调用_exit()或_Exit().
    进程有5种正常终止方式:
(1)常见的一种是,在main函数中运行return语句,这点是等效于调用exit().
(2)调用exit()函数,其操作包含调用终止处理程序(由atexit()或on_exit()函数注冊,下文再细细说来)。然后关闭全部IO流等.
(3)调用_exit或_Exit函数.
(4)进程的最后一个线程在其启动例程中运行返回语句.可是,该线程的返回值不会用作进程的返回值.当最后一个线程从其启动例程返回时。该进程以终止状态0返回.
(5)进程的最后一个线程调用pthread_exit函数.
     3种异常终止方式:(在这里仅仅做了解,不细细讨论).
(6)调用abort.它产生SIGABRT信号,这个终止方式依靠信息传递机制.
(7)当进程接收到某些信号时,信号可由进程自身、其它进程或内核产生.
(8)最后一个线程对“取消”请求作出响应.
    无论进程是怎样终止。最后都会运行内核中的同一段代码.关闭全部文件描写叙述符,释放他全部的存储器等等.如:进程正常退出前须要运行注冊的退出处理函数(终止处理程序),刷新流缓冲区等操作,然后释放进程用户空间.而进程控制块PCB并不在这时释放.仅调用退出函数的进程属于一个僵死进程.
    僵死进程:在UNIX系统中。一个已经终止,可是其父进程尚未对其进行善后处理(获取终止子进程的信息,释放所占资源)的进程称为僵死进程.

2.exit()与return的差别

    函数exit()用于退出进程.在正式释放资源前,将以反序的方式运行由on_exit()函数和atexit()函数注冊的清理函数(终止处理程序)。同一时候刷新流缓冲区.C语言keywordreturn与exit()在main函数(注意:仅仅是在main函数。在其它地方,是不相同的)中完毕相同的操作。但两者有本质的差别:
(1)return退出当前函数,exit()函数退出当前进程;因此,在main函数里。return(0)和exit(0),完毕一样的功能.
(2)return仅从子函数中返回,并不退出进程.调用exit()时要调用一段终止处理函数,然后关闭全部的IO流.以下的样例1是专门讲述这点差异的.

3.exit()函数

头文件:#include <stdlib>
定义函数:void exit(int status);
函数说明:
    exit()函数用来正常终止眼下进程的运行,并把參数status(称之为终止状态)返回给父进程,而进程全部的缓冲区数据自己主动写回并关闭全部IO流.
样例1:在main函数使用死循环的方式调用子函数fun().在这个样例能够看到exit和return的差异.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int fun()
{
        printf("fun
");
        sleep(1);

        //读者切换调用,体会一下
        //return 0;
        exit(0);
}

int main()
{
        int i;
        i++;
        printf("i = %d 
"。i);
        while(1)
                fun();
        return 0;
}

   

    在上面这个样例中,我们看到假设在子函数中使用exit(),则循环仅仅运行一次。假设在子函数中使用returnkeyword,则死循环将一直运行下去.

4._exit()函数

头文件:#include <unistd.h>
定义函数:void _exit(int status);
函数说明:
    _exit()等价于_Exit().
    _exit()函数用来马上结束程序的运行,并把參数返回给父进程。不调用不论什么终止处理程序而直接退出.此函数调用后不会返回。而且会传递SIGCHLD信号给父进程。父进程能够由wait()函数取得子进程结束的状态.注意:_exit()不会处理标准IO缓冲区,假设更新缓冲区请使用exit().
样例2:查看exit与_exit函数的差别.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
        printf("output
");
        printf("content int buffer"); //不带


        //_exit(0);             //仅仅输出output。没有清理缓冲区(没刷新)
        exit(0);                //改为此句,将输出content int buffer
        //return 0;
}

   

    由样例2能够看出。_exit()调用退出时,没有清理刷新缓冲区.终止一个程序时,_exit()马上进入内核,而exit()则先要运行一些清理处理程序.

5.atexit()和on_exit()函数

头文件:#include<stdlib.h>
定义函数:
int atexit(void (*function)(void));
int on_exit(void (*function)(int 。 void *), void *arg);
返回值:如成功返回0,若出错返回非0值.
函数说明:
    函数atexit()和on_exit()用来注冊运行exit()函数前运行的操作函数。事实上现使用了回调函数的方法.按ISO C规定。一个进程能够注冊多达32个函数,这些函数被称之为终止处理程序.查看实际能够注冊多少个终止处理程序,能够通过调用sysconf()函数获得.exit()调用这些函数的顺序与他们登记时候的顺序相反.同一个函数如若登记多次,则也会被调用多次.函数atexit()和on_exit()两者的差异不过在函数的參数上.
    当中atexit()函数的參数是一个函数的地址,类型为void (*function)(void);当调用此函数时无需向它传递不论什么參数,也不期望它返回一个值.
    而on_exit()函数的參数是一个带參数的函数。类型为void (*function)(int , void *),在这个函数void (*function)(int , void *)中。第一个參数为退出的状态,在运行exit()函数时传递此參数值为exit()函数的參数.第二个參数为用户输入信息,一个无类型的指针。用户能够指定一段代码位置或输出信息.(这里有点拗口,结合以下的样例3看看.)
样例3:说明怎样使用atexit()函数.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
static void my_exit1();
static void my_exit2();

int main()
{
        int i=0;
        if(atexit(my_exit2)!=0)
        {
                printf("can't register my_exit2");
        }
        for(i=0; i<3; i++)
        {
        if(atexit(my_exit1)!=0)
                {
                        printf("can't register my_exit1");
                }
        }

        printf("main exiting....
");
        return 0;
        //exit(0);//同return 0;
        //_exit(0);//这个就不同了
}

static void my_exit1()
{
        printf("first exit handler...
");
}
static void my_exit2()
{
        printf("second exit handler...
");
}


输出:

:main exiting....
:first exit handler...
:first exit handler...
:first exit handler...
:second exit handler...

    终止处理程序每注冊一次。就会被调用一次.在上述样例中,第一个终止处理程序被注冊了3次。所以也会被调用3次.且调用顺序是和注冊时的顺序是相反的,这让我们联想到栈的原理,先进后出,后进先出.
    注意:这里在main函数是调用return 0(和exit()一样),可是假设调用_exit(),输出结果就不一样了.程序仅仅会输出main exiting.....由于_exit()不会去调用清理工作的函数.
样例4:说明怎样使用on_exit()函数.
#include <stdio.h>
#include <stdlib.h>

static void test_exit(int status,void *arg);

int main()
{
        char *str = "How to use on_exit function...
";
        on_exit(test_exit,(void *)str);
        exit(1314);
        //return 520;
}
static void test_exit(int status,void *arg)
{
        printf("before exit()!
");
        printf("exit:%d
"。status);
        printf("arg=%s
"。(char *)arg);
}


输出:

:before exit()!
:exit:1314
:arg=How to use on_exit function...

    能够看出。on_exit()和exit()还有终止处理程序test_exit()之间的关系.函数test_exit()的两个參数都是从“别人”哪里得来的.注意了。这里假设是用return 520;效果也会一样哦,读者能够试试.
样例5:在终止处理程序中调用_exit()函数,这个有点奇葩啊,读者猜想一下会是神马结果呢.改良样例4,得到下面程序:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
static void my_exit1();
static void my_exit2();
static void my_exit3();

int main()
{
        int i=0;
        if(atexit(my_exit2)!=0)
        {
                printf("can't register my_exit2
");
        }
		 //新添加的部分
        if(atexit(my_exit3)!=0)
        {
                printf("can't register my_exit3
");
        }
        for(i=0; i<3; i++)
        {
        if(atexit(my_exit1)!=0)
                {
                        printf("can't register my_exit1
");
                }
        }

        printf("main exiting....
");
        //return 0;
        exit(0);
        //_exit(0);
}

static void my_exit1()
{
        printf("first exit handler...
");
}
static void my_exit2()
{
        printf("second exit handler...
");
}
static void my_exit3()
{
        printf("three exit handler...
");
        _exit(0);//注意这里了.加了_exit(0);
}


输出:

: main exiting....
:first exit handler...
:first exit handler...
:first exit handler...
:three exit handler...

    发现没有,“second exit handler...”这个没有输出,为什么?假设在当中一个终止处理程序中(atexit() or on_exit())调用了_exit()函数。那剩余的终止处理程序将不会得到调用。同一时候由exit()函数调用的其它终止进程步骤也将不会运行.

6.综述

    exit()退出会处理缓冲区。_exit()不会.资源不能浪费,分配出去的资源,要记得回收回来,给更须要的进程使用.不要站着茅坑不拉屎.
    atexit()和on_exit()注冊终止处理程序。假设用户在结束进程前,想干一下别的事。能够用这两个函数注冊.
    exit()和return等价,仅在main函数中.

    _exit()和_Exit()等价,不论什么时候.

參考阅读:

[1] exit()函数使用说明.http://blog.csdn.net/u010006102/article/details/39737155.

[2] _exit()函数使用说明.http://blog.csdn.net/u010006102/article/details/39740101.

[3] atexit()函数使用说明.http://blog.csdn.net/u010006102/article/details/39740071.

[4] on_exit()函数使用说明.http://blog.csdn.net/u010006102/article/details/39740021.


笔者:个人能力有限,仅仅是学习參考...读者若发现文中错误,敬请提出.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台,静下心来。慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
原文地址:https://www.cnblogs.com/zfyouxi/p/5204052.html