之前总结了Linux的系统创建,主要是fork()函数和vfork()函数,最近总结了Linux进程的终止,主要的调用是_exit()和exit().

先看看两个函数的原型以及各自属于的头文件,可以发现这两个方法的区别

_exit()函数:

    #include <unistd.h>  

    void _exit(int status);  

从_exit()的头文件能够发现,_exit()是属于Linux的系统调用, 只能在Linux或者是Unix上才支持这个调用。

其中,status定了进程的终止状态,其父进程可以通过wait()函数来获取这个状态,从而进行之后的执行操作。当status为0时,表示进程正常退出,反之则是非正常退出。调用_exit()会使进程总是成功终止,也就是说_exit()方法从不会返回。

此处需要注意的是,虽然status定义成了整型,但实际上只有低8位可用,其原因就是当以信号(signal)终止一个进程的时候,shell会将变量$?置为128与信号之和,以表征这一事实。如果这与进程调用_exit()时所使用相同status值混杂起来,将令shell无法分辨。(这个地方不是很理解)

exit()函数:

#include <stdlib.h>  

void exit(int status); 

从exit()的头文件可以看出,exit()是C语言的库函数,所以所有的C语言都支持这个方法。

exit()在调用的时候要做得工作会比较多,主要有如下几个操作:

  1. 调用退出处理程序(通过atexit()和on_exit()注册的函数),并且在有多个退出处理程序时,执行顺序与注册顺序相反。
  2. 刷新stdio流缓冲区;
  3. 使用有status提供的值执行_exit()函数

我们通常在写程序的时候,在main()函数结尾只是用了return n;来结尾,在这个地方,return n; 就相当于exit(n),在结束的时候主函数会将返回值作为调用exit()函数的参数。这个地方本人有个疑问,在exit()函数调用_exit()时,其参数使用前面的n,而在_exit(int status)中,status为0表示程序正常结束,如果在return的时候,指定的n不为0,是一个其他的数,Linux内部会怎么处理呢?

其实在进程终止的时候,还有一些更细致的操作,由于本人目前能力有限,先不做讨论。

刚刚在前面提到了退出处理程序,现在来看看退出处理程序。

使用退出处理程序的原因就是,我们调用的exit()是C语言的库函数,而库函数对于进程的退出并没有实际控制的权利,所以无法在进程退出时调用系统特定的清理函数,所以退出处理函数就应运而生。

GUNC 提供了一下两种方式来注册退出处理函数:

    #include <stdlib.h>  

    int atexit(void (*func)(void));  

    //退出处理函数的定义  

    void func(void) {
/* performance */
}

需要注意的是:

  1. atexit()函数在出错的时候返回的是非0值,不仅仅是负值;
  2. 同时,在退出处理函数中如果访问了此前mian()函数中本地变量,那么main()函数的返回会导致未定义的行为;
  3. 当有多个退出处理程序的时候,退出处理程序的调用顺序与之策顺序是相反的,这一点的逻辑是,先注册的通常是更为基本的清理动作,可能需要在后续注册的函数后再执行;
  4. 一旦退出处理程序在无法返回——调用了_exit()或者因为信号而终止,其后的处理程序将不再执行。

以上的atexit()有两个局限,第一是退出处理程序不能获取当前进程退出时的状态,而根据进程退出状态来做相应的操作可以是支持的;第二就是不能给退出处理程序传递参数。

所以glibc提供了一个非标准的替代方法:on_exit()。其定义如下:

    #define _BSD_SOURCE
#include <stdlib.h> int on_exit(void (*func)(int, void *),void *arg); //退出处理函数定义
void func(int status, void *arg) {
/* Performace */
}

和atexit()函数类似,on_exit()的出错时返回值为非0。而on_exit()还不是所有标准都支持,还是应该尽量避免。

atexit()和on_exit()注册的函数属于同一个函数列表,在执行时与注册的顺序相反。

最后给一个例子仅供大家参考:

#define _BSD_SOURCE
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h> static void atexitFunc1(void) {
printf("atexit function 1 called\n");
} static void atexitFunc2(void) {
printf("atexit function 2 called\n");
} static void onexitFunc(int exitStatus, void *arg) {
printf("on_exit function called: status=%d, arg=%ld\n",exitStatus, (long) arg);
} int main(int argc, char *argv[]) {
if(on_exit(onexitFunc, (void *) ) != )
perror("on_exit 1");
if(atexit(atexitFunc1) != )
perror("atexit 1");
if(atexit(atexitFunc2) != )
perror("atexit 2");
if(on_exit(onexitFunc, (void *) ) != )
perror("on_exit 2");
exit();
}

执行的结果如下:

    on_exit function called: status=, arg=
atexit function called
atexit function called
on_exit function called: status=, arg=

希望和大家多交流

Linux系统调用:进程的终止的更多相关文章

  1. Linux查看进程和终止进程的技巧

    1. 在LINUX命令平台输入1-2个字符后按Tab键会自动补全后面的部分(前提是要有这个东西,例如在装了tomcat的前提下,输入tomcat的to按tab). 2. ps 命令用于查看当前正在运行 ...

  2. 《linux下进程的创建,执行,监控和终止》

    <linux下进程的创建,执行,监控和终止> http://blog.csdn.net/miss_acha/article/details/43671047 http://blog.csd ...

  3. Linux下进程终止过程

    不管是在什么系统中,当进程终止之后.系统都须要释放进程占有的资源. 否则.系统资源会被耗尽. 以下将具体说明Linux系统中,进程终止的过程. 进程终止方式 linux的进程终止方式有8种,当中5种是 ...

  4. [转载]了解Linux的进程与线程

    本文转自Tim Yang的博客http://timyang.net/linux/linux-process/ .对于理解Linux的进程与线程非常有帮助.支持原创.尊重原创,分享知识! 上周碰到部署在 ...

  5. [Linux]系统调用理解(2)

    本文介绍了Linux下的进程概念,并着重讲解了与Linux进程管理相关的4个重要系统调用getpid,fork,exit和_exit,辅助一些例程说明了它们的特点和使用方法. 关于进程的一些必要知识 ...

  6. [Linux]Linux系统调用列表

    本文列出了大部分常见的Linux系统调用,并附有简要中文说明. 以下是Linux系统调用的一个列表,包含了大部分常用系统调用和由系统调用派生出的的函数.这可能是你在互联网上所能看到的唯一一篇中文注释的 ...

  7. Linux 结束进程

    一个进程由于以下5个原因中的一个终止 --main函数调用return; --调用exit函数--C语言库函数: --调用_exit函数--系统调用 --调用abort函数 --被一个信号终止.(ki ...

  8. linux中进程控制

    1.进程标识 每个进程都有一个非负整型表示的唯一的进程ID.进程ID标识符总是唯一的.  虽然进程ID是唯一的,但某个ID被回收后,ID号是可以复用的. ID为0的进程通常是调度进程(其常常被称交换进 ...

  9. 关于Linux系统调用,内核函数【转】

    转自:http://blog.csdn.net/ubuntulover/article/details/5988220 早上听人说到某个程序的一部分是内核态,另一部分是用户态,需要怎么怎么.当时突然想 ...

随机推荐

  1. pandas,对dataFrame中某一个列的数据进行处理

    背景:dataFrame的数据,想对某一个列做逻辑处理,生成新的列,或覆盖原有列的值   下面例子中的df均为pandas.DataFrame()的数据   1.增加新列,或更改某列的值 df[&qu ...

  2. CodeWarrior 10 配置Jlint初始化文件

    新建一个项目之后,飞思卡尔的仿真器的配置不如德州仪器那么简单.他需要一些配置. 当我们新建一个工程后,可以采取如下步骤配置Jlint: 1.右击工程名,选择属性. 2.在Run/Debug Setti ...

  3. LayUI左侧菜单无法保持选中状态

    1.问题描述:一般的左侧菜单都会是动态添加的模块,利用循环把模块名和链接地址逐个显示出来如下图 但是问题来了,只要点任何二级菜单就不会保持左侧菜单当前一级菜单和二级菜单选中状态. 2.分析原因:因为模 ...

  4. Python Selenium系列学习

    以下记录刚接触Python Selenium操作Web UI的学习问题: 1.python selenium三种等待方式: ①强制等待:time.sleep(value):设置等待最简单的方法就是强制 ...

  5. SQL0803问题 键值重复

    工作中遇到SQL0803问题  使用DB2AS400数据库 报数据库键值重复错误 经同事分析为索引的起始值与当前已有记录的最大索引值不匹配造成的,验证过程如下: 1.SELECT max(被索引字段) ...

  6. python3作业:模拟登录

    __author__ = "bin007" customer = {}#存储用户信息#处理用户信息文件try: with open('login.txt','r',encoding ...

  7. .Net代码控制PrivateBinPath和ConfigurationFile的位置

    .Net的WinForm程序有的时候让人很烦的是,在执行目录下总是一大堆的DLL,配置文件,最少则是个以下,多的时候怕有四五十个吧……,自己程序中的类库,第三方的类库……加载一起让人感觉乱糟糟的,非常 ...

  8. docker image 详解

    docker iamge docker 镜像: [root@localhost ~]# docker image --help Usage: docker image COMMAND 管理镜像 Com ...

  9. k8s中yaml文常见语法

    在k8s中,所有的配置都是 json格式的.但为了读写方便,通常将这些配置写成yaml 格式,其运行的时候,还是会靠yaml引擎将其转化为json,apiserver 也仅接受json的数据类型. y ...

  10. MathExam Lv2

    一个大气又可爱的算术题----211606360 丁培晖 211606343 杨宇潇 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) ...