摘要:本文主要讲述进程的终止方式,以及怎样使用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. keil mdk中如何确保某一段程序不被优化掉

    使用mdk编程,假如有一个有用的函数你定义了但是没有显式的调用,mdk在默认方式下,将会把这个函数从整个程序总删除掉,以节省ROM. 比如,你在ROM的0x00002000处定位了一个函数,假设为vo ...

  2. Flex中如何通过horizontalTickAligned和verticalTickAligned样式指定线图LineChart横竖方向轴心标记的例子

    原文http://blog.minidx.com/2008/12/03/1669.html 接下来的例子演示了Flex中如何通过horizontalTickAligned和verticalTickAl ...

  3. 全国计算机等级考试二级教程-C语言程序设计_第6章_字符型数据

    #include <stdio.h> main() { char c; char d; c = ; d = '; if (c == d) { printf("yes\n" ...

  4. 个人封装的一个Camera类

    好久不写博客了,代码写了不少,但大多数都是拿来主义,要不是网上,要不就是自己曾经的代码拼装. 新工作是搞Android开发的,近期任务要求我封装一个Carmera类,自己也认为还是封装以后方便使用,弄 ...

  5. 404 Not Found The requested URL * was not found on this server

    1. 把从SVNcheckout下来的代码搭建起来.CakePHP+mysql.改动数据库配置. 2. 配置虚拟主机,发现訪问不了/user/login这个URL,报这个错误:404 Not Foun ...

  6. Android 常用代码大集合 [转]

    [Android]调用字符串资源的几种方法   字符串资源的定义 文件路径:res/values/strings.xml 字符串资源定义示例: <?xml version="1.0&q ...

  7. html系列教程--描述

    什么是 HTML? HTML 是用来描述网页的一种语言. HTML 指的是超文本标记语言 (Hyper Text Markup Language) HTML 不是一种编程语言,而是一种标记语言 (ma ...

  8. ORACLE EBS BOM 展开(使用标准程序bompexpl.exploder_userexit展开)

    create or replace package cux_bom_pub is PROCEDURE bom_expand_to_temp( p_organization_id number, p_i ...

  9. 获取UIButton的一些属性

    获取文字  button.currentTitle 更多如下: @property(nullable, nonatomic,readonly,strong) NSString *currentTitl ...

  10. linux创建用户和组

    linux下创建用户(一) Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.用户的账号一方面可以帮助系 ...