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

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

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

回收进程用户空间资源 exit()函数 _exit()函数 atexit()函数 on_exit()函数的更多相关文章

  1. linux下在用户空间访问I/O端口的ioperm和iopl函数

    1.ioperm函数      功能描述:为调用进程设置I/O端口访问权能.ioperm的使用需要具有超级用户的权限,只有低端的[0-0x3ff] I/O端口可被设置,要想指定更多端口的权能,可使用i ...

  2. linux 用户空间与内核空间——高端内存详解

    摘要:Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对 ...

  3. 用户空间与内核驱动的交互过程 — ioctl

    在Linux内核模块的开发过程中,经常涉及到运行在用户空间上的应用程序与内核模块进行交互,ioctl系统调用是常用的一种方式.本文并不涉及vlan的具体原理,仅通过vconfig与vlan内核模块进行 ...

  4. linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数(转载)

    一,进程终止有5种方式: 正常退出: 从main函数返回 调用exit 调用_exit 异常退出: 调用abort 由信号终止 二,exit和_exit区别: 关于_exit(): #include ...

  5. exit()与_exit()函数的区别(Linux系统中)

    注:exit()就是退出,传入的参数是程序退出时的状态码,0表示正常退出,其他表示非正常退出,一般都用-1或者1,标准C里有EXIT_SUCCESS和EXIT_FAILURE两个宏,用exit(EXI ...

  6. Linux内存点滴:用户进程内存空间

    原文出处:PerfGeeks 经常使用top命令了解进程信息,其中包括内存方面的信息.命令top帮助文档是这么解释各个字段的.VIRT , Virtual Image (kb)RES, Residen ...

  7. Linux内存点滴 用户进程内存空间

    Linux内存点滴 用户进程内存空间 经常使用top命令了解进程信息,其中包括内存方面的信息.命令top帮助文档是这么解释各个字段的. VIRT, Virtual Image (kb) RES, Re ...

  8. exit()和_exit()函数

    进程就好比人一样有其生命,我们通过fork()函数来创建一个进程,那么我们又是如何来中止进程呢. 进程退出 1.在Linux中任何让一个进程退出 进程退出表示进程即将结束.在Linux中进程退出分为了 ...

  9. 进程退出exit、_exit、abort

    分为正常退出,异常退出 正常退出的方法: 1.在main函数中执行return 2.调用exit函数 3.调用_exit  函数 ----------------------------------- ...

随机推荐

  1. fieldset 使用小案例

    有初学者问到如何做出如下页面: 对应的代码如下: <fieldset> <legend>★审核状态</legend> <input name="st ...

  2. android PopupWindow显示位置

    PopupWindow的显示及位置设置 window.showAtLocation(parent, Gravity.RIGHT | Gravity.BOTTOM, 10,10); 第一个参数指定Pop ...

  3. 大数据为什么要选择Spark

    大数据为什么要选择Spark Spark是一个基于内存计算的开源集群计算系统,目的是更快速的进行数据分析. Spark由加州伯克利大学AMP实验室Matei为主的小团队使用Scala开发开发,其核心部 ...

  4. Formiko总结整数十进制转换二进制原理

    引子: 为什么十进制转二进制的“辗转相除记录余数倒序输出”的算法是正确的?这个问题陪伴了Formiko半年. 实践: 实践一:把十进制数100转换成二进制数的图   上图和和下图唯一的区别在最后一位上 ...

  5. opensatck 使用devstack在 laptop上的 网络配置

    http://docs.openstack.org/developer/devstack/guides/neutron.html Physical Network Setup In most case ...

  6. 网易云课堂_C语言程序设计进阶_第8周:图形交互程序

    8.2函数指针 8.2函数指针 #include <stdio.h> #include <stdlib.h> void f(int i) { printf("void ...

  7. 自定义和扩展 SharePoint 2010 Server 功能区

    了解构成 SharePoint 2010 服务器功能区的组件以及如何通过演练两个功能区自定义项方案来自定义功能区. 适用范围: Microsoft SharePoint Foundation 2010 ...

  8. html标签总结。

    接触了一段时间的html和css,发现了其中的乐趣.在写代码时一定要仔细,很有可能一个细微的错误便会导致页面的错误 总结了一下html标签. <html></html> 创建一 ...

  9. .net通用权限框架B/S (四)--DAL数据层以及数据接口

    数据层以及数据接口设计如下图(以g_orga组织机构和g_role角色)为例,这几个类可以通过.tt模版生成 设计参考学习http://www.cnblogs.com/hanyinglong/arch ...

  10. 【转】SQL Server查询字段说明

    select c .name, isnull(ETP .value, '') as Des FROM syscolumns c inner join systypes t on c. xusertyp ...