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

来源:互联网 发布:java编码规范 编辑:程序博客网 时间:2024/06/08 02:39
摘要:本文主要讲述进程的终止方式,以及如何使用exit()函数来终止进程,回收进程用户空间资源;分析了exit()函数与_exit()函数,return关键字的差异.同时详细解读了如何使用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语言关键字return与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\n");        sleep(1);        //读者切换调用,体会一下        //return 0;        exit(0);}int main(){        int i;        i++;        printf("i = %d \n",i);        while(1)                fun();        return 0;}

   

    在上面这个例子中,我们看到如果在子函数中使用exit(),则循环只执行一次;如果在子函数中使用return关键字,则死循环将一直执行下去.

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\n");        printf("content int buffer"); //不带\n        //_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....\n");        return 0;        //exit(0);//同return 0;        //_exit(0);//这个就不同了}static void my_exit1(){        printf("first exit handler...\n");}static void my_exit2(){        printf("second exit handler...\n");}


输出:

: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...\n";        on_exit(test_exit,(void *)str);        exit(1314);        //return 520;}static void test_exit(int status,void *arg){        printf("before exit()!\n");        printf("exit:%d\n",status);        printf("arg=%s\n",(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\n");        } //新增加的部分        if(atexit(my_exit3)!=0)        {                printf("can't register my_exit3\n");        }        for(i=0; i<3; i++)        {        if(atexit(my_exit1)!=0)                {                        printf("can't register my_exit1\n");                }        }        printf("main exiting....\n");        //return 0;        exit(0);        //_exit(0);}static void my_exit1(){        printf("first exit handler...\n");}static void my_exit2(){        printf("second exit handler...\n");}static void my_exit3(){        printf("three exit handler...\n");        _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.


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

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台,静下心来,慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 0
原创粉丝点击