回收进程用户空间资源 exit()函数 _exit()函数 atexit()函数 on_exit()函数
来源:互联网 发布:java编码规范 编辑:程序博客网 时间:2024/06/08 02:39
摘要:本文主要讲述进程的终止方式,以及如何使用exit()函数来终止进程,回收进程用户空间资源;分析了exit()函数与_exit()函数,return关键字的差异.同时详细解读了如何使用atexit()和on_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系统中,一个已经终止,但是其父进程尚未对其进行善后处理(获取终止子进程的信息,释放所占资源)的进程称为僵死进程.
(1)return退出当前函数,exit()函数退出当前进程;因此,在main函数里,return(0)和exit(0),完成一样的功能.
(2)return仅从子函数中返回,并不退出进程.调用exit()时要调用一段终止处理函数,然后关闭所有的IO流.下面的例子1是专门讲述这点差异的.
定义函数:void exit(int status);
函数说明:
exit()函数用来正常终止目前进程的执行,并把参数status(称之为终止状态)返回给父进程,而进程所有的缓冲区数据自动写回并关闭所有IO流.
例子1:在main函数使用死循环的方式调用子函数fun().在这个例子可以看到exit和return的差异.
定义函数:void _exit(int status);
函数说明:
_exit()等价于_Exit().
_exit()函数用来立即结束程序的执行,并把参数返回给父进程,不调用任何终止处理程序而直接退出.此函数调用后不会返回,并且会传递SIGCHLD信号给父进程,父进程可以由wait()函数取得子进程结束的状态.注意:_exit()不会处理标准IO缓冲区,如果更新缓冲区请使用exit().
例子2:查看exit与_exit函数的区别.
定义函数:
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()函数.
: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()函数.
:exit:1314
:arg=How to use on_exit function...
可以看出,on_exit()和exit()还有终止处理程序test_exit()之间的关系.函数test_exit()的两个参数都是从“别人”哪里得来的.注意了,这里如果是用return 520;效果也会一样哦,读者可以试试.
例子5:在终止处理程序中调用_exit()函数,这个有点奇葩啊,读者猜想一下会是神马结果呢.改良例子4,得到以下程序:
:first exit handler...
:first exit handler...
:first exit handler...
:three exit handler...
发现没有,“second exit handler...”这个没有输出,为什么?如果在其中一个终止处理程序中(atexit() or on_exit())调用了_exit()函数;那剩余的终止处理程序将不会得到调用,同时由exit()函数调用的其他终止进程步骤也将不会执行.
atexit()和on_exit()注册终止处理程序,如果用户在结束进程前,想干一下别的事,可以用这两个函数注册.
exit()和return等价,仅在main函数中.
进程终止、回收资源
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
- 回收进程用户空间资源 exit()函数 _exit()函数 atexit()函数 on_exit()函数
- 进程终止函数:abort, atexit, exit, _exit, _Exit
- exit()函数,_exit()函数,_EXIT()函数 和atexit函数
- atexit函数和on_exit函数
- atexit(函数和on_exit()函数
- 结束程序函数exit、 _exit、 atexit区别
- exit,_exit.atexit,return,strerror 函数
- _exit( )、exit( )、atexit( )函数比较思考
- Linux下的atexit,exit,_exit函数
- exit和_exit函数,atexit函数 abort函数
- exit和_exit函数,atexit函数 abort函数
- 进程终止函数:abort, atexit, exit, _exit, _Exit http://blog.sina.com.cn/s/blog_605f5b4f0100x3v0.html
- linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数
- linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数
- linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数
- exit()和atexit()函数
- atexit() 和 exit() 函数
- exit()和_exit()函数
- please set a system env PAODING_DIC_HOME or Config paoding.dic.home in paoding-dic-home.properties p
- Clustering of residential areas based on residential conditions
- Java学习第一例:HelloWorld
- Uva10557XYZZY
- 康托展开及其逆运算
- 回收进程用户空间资源 exit()函数 _exit()函数 atexit()函数 on_exit()函数
- CMakeLists.txt与Makefile 的区别
- 云计算厂商应该避免的3种销售和市场手段
- 聚类之K-means均值聚类
- 597- 使用的hint 自相矛盾
- 互联网协议入门
- VirtualBox + Android-x86 配置全攻略
- 可在PC上使用Kinect的OpenKinect
- 高精度-大菲波数