Linux--进程的终止(正常和异常)、钩子函数、exit函数和_exit或_Exit函数
进程的终止
正常终止
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函数相关推荐
- linux进程无条件终止,kill - 终止进程/发送信号
Linux命令之kill - 终止进程/发送信号 用途说明 kill命令用于终止指定的进程(terminate a process),是Unix/Linux下进程管理的常用命令.通常,我们在需要终止某 ...
- Linux进程的详细内容
1 进程 1.1 程序的顺序执行与并发执行 程序的顺序执行: 程序的各操作步骤之间依序执行,程序与程序之间串行执行,称为顺序执行.顺序执行时单道程序系统中的程序的运行方式. 特点: 顺序性:一个操作结 ...
- 【Linux】linux进程--进程控制:进程创建、进程终止、进程等待、进程程序替换
目录 1.进程创建 1)重温fork():让正在运行的进程创建出来一个子进程:从已存在的进程中创建一个新的进程,新进程为子进程而远进程为父进程. 2)fork内部完成的事情 3)用户空间 & ...
- 高效管理 Linux 进程:如何后台执行程序、查看进程、终止任务
目录 前言 一.nohup命令详解 1-1.nohup命令介绍 1-2.语法格式 1-2-1.基础语法介绍 1-2-2.执行脚本文件 1-2-3.执行python文件 1-2-4.拓展延申:在服务器上 ...
- Linux中进程的创建、进程的终止、进程的等待、进程的程序替换
进程的创建 在进程的创建中,我们一个非常重要的函数 fork()函数,fork()函数会创建一个新的进程,为原有进程的子进程,原有就为父进程. 我们来看一下fork()函数的原型. #include ...
- Linux 进程控制 :进程创建,进程终止,进程等待,程序替换
进程创建 进程终止 进程等待 程序替换 进程创建 fork函数 创建一个子进程,父子进程代码共享,数据独有 #include <unistd.h> pid_t fork(void); 返回 ...
- Linux进程终止命令kill或killall笔记
在linux命令下,如果需要终止某个进程,可以使用kill或者killall等命令来实现.终止命令的原理都是向linux内核发送一个系统操作的信号以及某个进程的ID,然后系统内核会根据指定的进程ID进 ...
- linux 进程开始与终止
exit(0) 表示程序正常退出: exit(1)/exit(-1) 表示程序异常退出: exit() 结束当前进程/当前程序/,在整个程序中,只要被调用就结束,返回参数值: return() 是当前 ...
- linux进程异常退出分析,ECS Linux程序异常退出提示“out of memory”的临时解决办法...
ECS Linux上的程序会出现异常退出的情况,退出的原因多数是因为系统内存不足,Linux内存不足通常会触发 Linux 内核里的 Out of Memory (OOM) killer,OOM ki ...
- Linux x86_64内核终止D状态的进程
在上一篇文章< Linux x86内核终止D状态的进程>中,我展示了32位x86系统中如何编码杀死D进程.本文我将展示一种64位x86系统上的方法. 说实话,64位系统上做 ...
最新文章
- Myeclipse启动报错: Invalid 'log4jConfigLocation' parameter
- 进临界区(关全局中断)是否会影响数据的接收?
- JS过滤空格,回车符。
- 启动项目后,FileItemFactory 错误
- UVC协议USB视频捕获设备定义
- qq流浏览器网页版_如何使QQ浏览器浏览简洁
- jquery html页面跳转,HTML 链接
- 开关造成的毛刺_干冰清洗机模具清洗机干冰去毛刺机注意事项
- 算法 python实现(一) 基本常识
- oracle 运营维护_总结几个ORACLE数据库日常运维常用的命令(持续更新)
- mybatis mysql 中文乱码_mybatis连接mysql数据库插入中文乱码
- jQuery 源码系列(十八)class 相关操作
- Windows远程访问Linux (Ubuntu)服务器
- php二维数组按照键值排序的方法
- java和vue的狱警管理系统监狱系统狱务管理系统
- IBM SPSS Modeler 【4】 神经网络模型的测试验证
- Word文字怎么居中对齐
- java big5_BIG5编码表
- tp6多表联合查询的几种方式(模糊搜索+分页+字段限制)
- paddle video_tag paddle.fluid.io.xmap_readers