回收进程用户空间资源 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\n");
sleep(1); //读者切换调用,体会一下
//return 0;
exit(0);
} int main()
{
int i;
i++;
printf("i = %d \n"。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\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.

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

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台,静下心来。慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
上一篇:java多线程的(一)-之java线程的使用


下一篇:Android Native层异步消息处理框架