码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-10-03 13:40:44      阅读:358      评论:0      收藏:0      [点我收藏+]

标签:unix   exit函数   _exit函数   atexit函数   on_exit函数   

摘要:本文主要讲述进程的终止方式,以及如何使用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.


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

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台,静下心来,慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

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

标签:unix   exit函数   _exit函数   atexit函数   on_exit函数   

原文地址:http://blog.csdn.net/u010006102/article/details/39754817

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!