标签: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