文章导读
大家好,我是陈景序,今天我们来聊聊进程控制中的一个小知识点——进程终止的三种状态。你知道怎么判断一个进程是正常结束、意外结束还是异常终止吗?这篇文章会帮你解答这个问题,读完之后你就能对进程终止的状态有更清晰的认识了。
进程终止
进程终止,简单来说就是进程运行结束。它有两种含义:一种是正常结束,即代码运行完毕;另一种是意外结束,即代码因为某种异常意外终止。就像考试,正常考完会有成绩,而缺考或作弊就没有成绩。进程的终止状态也分为三种:代码运行完毕但结果不正确、代码运行完毕但结果不正确、代码异常终止。
如何知道进程终止的状态
每一个进程终止之后都会给其父进程发送一个退出码和退出信号。退出码用来反映进程退出的结果,一般来说0表示结果正确,非0表示结果错误。而退出信号则表示是否发生异常,以及发生了什么异常。在Linux下,退出码的信息可以用strerror()函数来查看。
退出码
观察以下代码输出部分退出码:
// 代码示例
很清楚地可以看到,退出码0-133都有其对应的错误信息描述。退出码只有在没有发生异常的情况才有其意义。一旦发生异常,则说明程序压根就没有执行完,这时候的退出码也就没有意义。
信号
Linux信号,它允许进程和内核中断其它程序。一个信号就是一条小消息,它通知进程系统中发生了一个某种类型的事件。我们可以用
kill -l指令查看这些信号。每种信号都对应着某种系统事件。底层的硬件异常是由内核异常处理程序处理的,正常情况下,对用户进程而言是不可见的。信号提供了一种机制,通知用户进程发生了这些异常。比如一个程序试图除以0,那么内核就给它发送一个SIGFRE信号(8)。如果一个进程执行了一条非法的指令,那么内核就发送给它一个SIGILL信号(4)。
信号术语
传送一个信号分为发送信号和接收信号两个步骤组成。
- 发送信号:内核通过更新目的进程上下文中的某个状态,发送一个信号给目的进程。发送信号有以下两个原因:
- 1.内核检测到一个系统事件,主动发送信号。比如上面提到的除0错误或者子进程终止(子进程终止时会给其父进程发送一个信号)。
- 2.一个进程调用了kill函数,显示的要求内核发送一个信号给目的进程,包括它自己。比如用
kill -9杀死某个进程。
- 接收信号:当目的进程被内核强制以某种方式对信号的发送作出反应时,他就接收了信号。进程可以忽略这个信号,终止或者通过执行一个成为信号处理程序的用户层函数捕获这个信号。
进程常见的退出方法
正常退出:
- 1. 在main函数用return返回。这也是我们最常用的退出方式。return在普通函数中返回的是函数的结果,而在main函数里返回的就是退出码。
- 2. 调用exit函数。
- 3. 调用_exit函数。
其中不同于return的是,exit和_exit可以在代码的任何位置终止程序。并且在main函数中return n实际上是在执行exit(n),因为调用main的运行时函数会将main的返回值当做exit的参数。
异常退出:用
kill指令发送相关指令强制退出进程,或者ctrl+c键发送键盘中断。我们可以使用
$?查看最近一次进程退出码的信息。
exit函数与_exit函数的区别
首先讲_exit函数。
#include
void _exit(int status);
1._exit() 函数是 POSIX 标准中定义的一个系统调用,通常在
头文件中声明。
2. 调用 _exit() 函数会立即终止进程的执行,不会执行任何清理操作,也不会关闭任何文件描述符。
exit
#include
void exit(int status);
1.exit是c标准库下的一个函数,本质上是对_exit的封装。
2. 调用 exit() 函数会立即终止进程的执行,并且会执行一系列清理操作、关闭标准 I/O 流、刷新缓冲区等。
exit函数终止程序的过程最终是通过调用_exit函数来完成的。但是在调用_exit之前,库函数的exit还做了其他的工作:执行用户通过 atexit或on_exit定义的清理函数。关闭所有打开的流,所有的缓存数据均被写入(刷新缓冲区)。
小结与拓展
好了,今天我们就聊到这里。通过这篇文章,你应该对进程终止的三种状态有了更清晰的认识。如果你对进程控制还有其他疑问,欢迎在评论区留言交流。我是陈景序,来自websoft网络软件专家(www.phpwebsoft.com),如果你对PHP和Web开发有兴趣,欢迎关注我们的网站,了解更多精彩内容。