进程的终止

正常终止

1、从main函数返回
2、调用exit
3、调用_exit或_Exit
4、最后一个线程从其启动例程返回
5、最后一个线程调用pthread_exit

异常终止

1、调用abort
2、接到一个信号并终止
3、最后一个线程对其取消请求作出响应

atexit():钩子函数

除了使用atexit()来实现钩子函数之外,还可以使用on_exit()来实现。

NAMEatexit - register a function to be called at normal process termination注册一个函数,在程序正常终止时将调用这个函数。SYNOPSIS#include <stdlib.h>int atexit(void (*function)(void));DESCRIPTIONThe  atexit()  function  registers the given function to be called at normal process termination, either via exit(3) or via return from the program's main().  我们在atexit()函数中注册了一个函数,在进程正常终止时,atexit()函数就会通过exit(3)或从程序中的main()返回,然后调用该函数。Functions so registered are called in the reverse order of their registration; no arguments are passed.注册的函数被调用的顺序与它们注册的顺序相反;不传递任何参数。The same function may be registered multiple times: it is called once for each registration.
同一个函数可以被注册多次:每注册一次都会被调用一次。

例子:

#include <stdio.h>
#include <stdlib.h>void f1(void)
{puts("f1() is working!");
}void f2(void)
{puts("f2() is working!");
}void f3(void)
{puts("f3() is working!");
}int main()
{puts("begin!");/*只是把三个函数挂到钩子上,不是调用*/atexit(f1);atexit(f2);//以逆序被调用atexit(f3);//什么时候才调用,即将执行exit(0)或return 0之前.puts("end!");return 0;
}

程序运行结果如下:

我们再来写一个伪代码说一下钩子函数有什么用处。

我们写程序时有可能会发生下面的情况。fd1 =open();
if(fd1<0)
{perror();exit(1);
}fd2 =open();
if(fd2<0)
{close(fd1);perror();exit(1);
}
......
......
fd100 =open();
if(fd100<0)
{close(fd1);close(fd2);close(fd3);......close(fd99);perror();exit(1);
}这就很麻烦,现在有钩子函数了,我们就可以这样做。
fd1 =open();
if(fd1<0)
{perror();exit(1);
}atexit(); -->作用是close(fd1);fd2 =open();
if(fd2<0)
{perror();exit(1);
}atexit(); -->作用是close(fd2);....
fd100 =open();
if(fd100<0)
{perror();exit(1);
}
atexit(); -->作用是close(fd100);

这里举打开文件的例子只是一种情况,我们还可以回收使用malloc开辟的没有释放的空间。

exit和 _exit或_Exit

exit

exit函数在手册的第三章。所以使用man 3 exit来查看。

NAMEexit - cause normal process termination引起正常进程终止SYNOPSIS#include <stdlib.h>void exit(int status);DESCRIPTIONThe exit() function causes normal process termination and the value of status & 0377 is returned to the parent (see wait(2)).

参数 status & 0377 (0377是八进制,换成二进制就是11111111)将被返回给父进程,也就是将status的第八位返回给父进程,第一位是符号位,也就是说status的范围是 -128 — +127。

通常,我们传入参数0,表示正常退出。其他表示非正常退出。

请问下面代码中这个return 0;是给谁看的?

#include <stdio.h>
#include <stdlib.h>int main()
{printf("Hello.\n");return 0;
}

答:这个return 0;是给当前进程的父进程看的。
我们将该程序通过gcc编译器编译之后,然后通过命令./xxx来执行,从" ./ " 可体现出来当前进程的父进程是shell,是shell将其创建出来的。

使用命令

echo $?

我查了下,
该命令的含义可以表示两种,
一种是最后运行的命令的返回值,即执行上一个指令的返回值 。
另外一种是最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

输出结果如下:

0

现在,我们将代码进行修改,将return 0;给去掉,再试着执行一下代码。
执行结果仍然是

Hello.

现在,再试着使用命令

echo $?

看(视频教程中)得到的结果:

7

我的执行结果是0。

那为什么是7呢?
是因为我们把return 0;这句代码去掉之后,上一条执行的命令就是printf(“Hello.\n”);

而printf的返回值就是成功输出字符的个数。

所以当我们使用

echo $?

打印出来的结果自然是printf的返回结果。

需要说明:
(视频中输出正常,打印出来的是7,所以返回的是上一个指令的返回值。)
(用我的虚拟机执行我的代码,输出正常,打印出来的是0,所以返回的是最后命令的退出状态。)

exit和 _exit或_Exit的区别

exit是库函数。
_exit 或 _Exit是系统调用。
所以,一定是 exit 依赖_exit或_Exit来实现函数功能。

那exit和 _exit或_Exit只是这一点的区别吗?

并不是的。

看下图。

从图中可以看到,在最下面是内核,也就是说当前的程序调用肯定要和内核发生交互(也就是系统调用的实现)。

虚线框是进程的虚拟空间。当用户在用户函数或main函数中或C启动历程中调用_exit或_Exit函数的时候,都是往图中的左侧走的,会直接跳出虚线框,代表的是直接终止。

而当用户在用户函数或main函数中或C启动历程中调用exit函数的时候,不是直接跳出虚线框的,而是先调用n多个终止处理程序(比如钩子函数),之后再调用标准I/O清理程序,然后才依赖于_exit或_Exit来结束当前的进程。

那什么时候应该用exit函数,什么时候又该用_exit或_Exit函数呢?

我们来举个例子来说一下。

int func()
{//可以返回0、1、2return 0/1/2;
}int main()
{int f;f=func();...........switch(f){  case 0:case 1:case 2://假设在当前情况下,没有0,1,2这种可能,说明程序出的问题在省略号部分,机器有可能是因为写越界,从而导致该部分将f的值做了修改。default://假设使用exit(1);那么程序就会先调用n多个终止处理程序(比如钩子函数),之后再调用标准I/O清理程序(刷新或同步各种内容),那么可能造成的问题可能就是故障扩大。//那在这种情况下应该怎么做呢?//1、除了应该调用_exit或_Exit函数,直接退出。//2、还可以使用信号abort();将当前进程直接杀死,顺便得到出错的原因。    }
}

Linux--进程的终止(正常和异常)、钩子函数、exit函数和_exit或_Exit函数相关推荐

  1. linux进程无条件终止,kill - 终止进程/发送信号

    Linux命令之kill - 终止进程/发送信号 用途说明 kill命令用于终止指定的进程(terminate a process),是Unix/Linux下进程管理的常用命令.通常,我们在需要终止某 ...

  2. Linux进程的详细内容

    1 进程 1.1 程序的顺序执行与并发执行 程序的顺序执行: 程序的各操作步骤之间依序执行,程序与程序之间串行执行,称为顺序执行.顺序执行时单道程序系统中的程序的运行方式. 特点: 顺序性:一个操作结 ...

  3. 【Linux】linux进程--进程控制:进程创建、进程终止、进程等待、进程程序替换

    目录 1.进程创建 1)重温fork():让正在运行的进程创建出来一个子进程:从已存在的进程中创建一个新的进程,新进程为子进程而远进程为父进程. 2)fork内部完成的事情 3)用户空间 & ...

  4. 高效管理 Linux 进程:如何后台执行程序、查看进程、终止任务

    目录 前言 一.nohup命令详解 1-1.nohup命令介绍 1-2.语法格式 1-2-1.基础语法介绍 1-2-2.执行脚本文件 1-2-3.执行python文件 1-2-4.拓展延申:在服务器上 ...

  5. Linux中进程的创建、进程的终止、进程的等待、进程的程序替换

    进程的创建 在进程的创建中,我们一个非常重要的函数 fork()函数,fork()函数会创建一个新的进程,为原有进程的子进程,原有就为父进程. 我们来看一下fork()函数的原型. #include ...

  6. Linux 进程控制 :进程创建,进程终止,进程等待,程序替换

    进程创建 进程终止 进程等待 程序替换 进程创建 fork函数 创建一个子进程,父子进程代码共享,数据独有 #include <unistd.h> pid_t fork(void); 返回 ...

  7. Linux进程终止命令kill或killall​笔记

    在linux命令下,如果需要终止某个进程,可以使用kill或者killall等命令来实现.终止命令的原理都是向linux内核发送一个系统操作的信号以及某个进程的ID,然后系统内核会根据指定的进程ID进 ...

  8. linux 进程开始与终止

    exit(0) 表示程序正常退出: exit(1)/exit(-1) 表示程序异常退出: exit() 结束当前进程/当前程序/,在整个程序中,只要被调用就结束,返回参数值: return() 是当前 ...

  9. linux进程异常退出分析,ECS Linux程序异常退出提示“out of memory”的临时解决办法...

    ECS Linux上的程序会出现异常退出的情况,退出的原因多数是因为系统内存不足,Linux内存不足通常会触发 Linux 内核里的 Out of Memory (OOM) killer,OOM ki ...

  10. Linux x86_64内核终止D状态的进程

    在上一篇文章< Linux x86内核终止D状态的进程>中,我展示了32位x86系统中如何编码杀死D进程.本文我将展示一种64位x86系统上的方法.         说实话,64位系统上做 ...

最新文章

  1. Myeclipse启动报错: Invalid 'log4jConfigLocation' parameter
  2. 进临界区(关全局中断)是否会影响数据的接收?
  3. JS过滤空格,回车符。
  4. 启动项目后,FileItemFactory 错误
  5. UVC协议USB视频捕获设备定义
  6. qq流浏览器网页版_如何使QQ浏览器浏览简洁
  7. jquery html页面跳转,HTML 链接
  8. 开关造成的毛刺_干冰清洗机模具清洗机干冰去毛刺机注意事项
  9. 算法 python实现(一) 基本常识
  10. oracle 运营维护_总结几个ORACLE数据库日常运维常用的命令(持续更新)
  11. mybatis mysql 中文乱码_mybatis连接mysql数据库插入中文乱码
  12. jQuery 源码系列(十八)class 相关操作
  13. Windows远程访问Linux (Ubuntu)服务器
  14. php二维数组按照键值排序的方法
  15. java和vue的狱警管理系统监狱系统狱务管理系统
  16. IBM SPSS Modeler 【4】 神经网络模型的测试验证
  17. Word文字怎么居中对齐
  18. java big5_BIG5编码表
  19. tp6多表联合查询的几种方式(模糊搜索+分页+字段限制)
  20. paddle video_tag paddle.fluid.io.xmap_readers

热门文章

  1. Kotlin 从零单排之小 tips
  2. Linux 下载 更新 google 浏览器 chrome
  3. 一招去掉电脑广告弹窗推荐界面
  4. MFC之 MapWinGis叠加必应瓦片地图
  5. 2021中国高校大数据挑战赛A题复盘+解题思路
  6. (七)云计算技术学习--OpenStack之Cinder和Swift
  7. html网页题,HTML及网页制作练习题-完整版
  8. 新品发布 | 纳芯微推出集成隔离电源的隔离485接口和隔离CAN接口芯片NSiP83086 / NSiP1042
  9. Evaluate函数运行时错误438
  10. VxWorks Tips