刷题外传之如何优雅的杀掉进程

进程(Process)是 Unix/Linux 系统下编程的核心知识。无论是小 Script 还是大 Daemon,启动后都是以进程的形势在 OS 中存在和执行。

进程的启动

启动进程其实最简单,假如我们有一段 Python Script (hello.py):

print “hello world”

运行它非常容易:

python hello.py

然后一个新的进程就产生了,由于代码很短,输出 “hello world” 之后进程就结束了。

启动进程的核心其实就是构建一个合法的命令行,通过 CLI / Process Controler 等方式调用它。程序的入口点只有一个,因此简洁、好调试。

进程的终结

重点来了,进程的终结相对复杂,来看看一些常见情况:

  • 程序运行很短(如上例),运行之后正常结束;
  • 程序运行时间长,小白用户烦了,Ctrl + C 硬关;
  • 程序运行时间长,程序员烦了,kill / pkill;
  • 程序运行时间长,一定要关死它(立即马上),kill -9

显然,关闭进程的方式多种多样,最理想的是,它正常结束。但生产环境中,你不能指望所有进程都顺顺利利,而且复杂一点的进程通常需要维护内部的数据状态,如果进程突然终止,但是内部维护的数据状态没有处理好,那就很糟糕了。

好吧,Ctrl + C 对于程序意味着什么呢?kill 和 kill -9 又有什么区别?

Signal

这就不得不说到 Signal.

Signal 是理解进程终止重要的概念,可以把它想象成一种 OS 内的消息,通常是在特殊的情况下由 OS 发给运行的 Program. 其实大家在写程序的时候已经用过它,比如你的程序 segement fault 了(悲催),其实 OS 就是发送了 “SIGSEGV” Signal 到你的程序然后 crash.

Signal 有很多,去 Wiki 一下,好像60多种,一般除非你要做 System Admin, 没必要全知道。但是最常见的几个要记住,很有用。

也许你猜到了,无论是 Ctrl + C, kill 还是 kill -9,其实都是由用户主动的发出 Signal 给一个特定的 Process.

  • Ctrl + C -> SIGINT
  • kill -> SIGTERM
  • kill -9 -> SIGKILL

这三个 Signal 一定要掌握。嗯,它们的区别呢?

Handle Signal

当你的程序收到 Signal 的时候,是不是一定就要退出呢?当然不是。

可能大家都有那种 ”按了一百遍 Ctrl + C, 程序就是关不掉,算你狠我还是重启吧“ 的情况,因为你的程序是可以 Handle Signal 的,看一段程序 (hello2.py):

import signal, time, sys def handle_signal(sign_num, frame): print “You pressed Ctrl + C” sys.exit(1) signal.signal(signal.SIGINT, handle_signal) for i in range(10000): print i time.sleep(1)

启动程序 python hello2.py 之后,它每一秒会打印一个新的数字。特别的是,我们给这个程序注册了一个 Handler SIGINT 的函数 (signal.signal(X, X) )

结果就是,在程序运行时,如果我们按 Ctrl + C, 那么 handle_signal 就会被执行,打印 “You pressed Ctrl + C”,然后退出。

如果你删掉 sys.exit(1) 这一行,那么 Ctrl + C 也没法干掉它了。

类似的,如果你为 SIGTERM 也注册一个 Handler 函数,当 Kill 发生的时候,同样可以执行 Handler 里面的代码。

对于 SIGINT & SIGTERM, 如果程序没有注册处理信号的方法,那么默认的行为是结束进程。

SIGKILL 是一个例外(From Kill -9),这个信号是程序内部无法 Catch & Handle 的,它的意思很明确:发给你,别废话,直接结束。

Handle Signal 的好处

前文提到过,复杂一点的程序都有很多的 State 需要维护,比如和数据库记录,文件的记录等等。Signal Handler 给了我们 cleanup 状态的机会。比如程序和数据库打交道,如果中途被 SIGITN 或者 SIGTERM,可以做点 logging (记录下为什么要结束),然后 mark job/state as failure 之类。别小看这些 cleanup function, 能处理好 edge cases 的程序才称得上健壮。

由于 SIGKILL 的特殊性,一旦执行,程序即使有 cleanup 也不能执行,因此请小心使用,千万不要图快什么都 Kill -9.

待续

本文只讨论一个进程的例子,但是大量的 Unix/Linux 进程(Process)在运行中会 Fork/Exec 新的进程。换句话说,一个结点的问题变成了一颗树的问题,那么信号如何传递,信号如何处理,下一篇文章我们继续讨论。

原文发布于微信公众号 - 包子铺里聊IT(baozitraining)

原文发表时间:2016-03-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏沈唁志

在PhpStorm中安装使用PHP_CodeSniffer编码规范检查工具

入职两天了,继续研究Swoole的框架,新公司有内部wiki,对于一些代码规范还是很重视的

1491
来自专栏圣杰的专栏

IdentityServer4 知多少

现在的应用开发层出不穷,基于浏览器的网页应用,基于微信的公众号、小程序,基于IOS、Android的App,基于Windows系统的桌面应用和UWP应用等等,这...

2812
来自专栏月色的自留地

新麦装机问题汇

1433
来自专栏zhangdd.com

windows系统Tomcat启动过程中找不到JAVA_HOME解决方法

在winserver上明明已经安装了JDK1.6并设置好了JAVA_HOME,可偏偏Tomcat在启动过程中找不到。

861
来自专栏信安之路

Window 提权基础

再加上个人的理解写出的关于 Windows 提权基础的文章,其中有些地方因为不太实用所以做了适当修改,感谢 @hl0rey 的帮助和建议。

2580
来自专栏大内老A

深入剖析ASP.NET的编译原理之二:预编译(Precompilation)

在本篇文章的第一部分:深入剖析ASP.NET的编译原理之一:动态编译(Dynamical Compilation),详细讨论了ASP.NET如何进行动态编译的,...

2496
来自专栏Timhbw博客

分享下平时我在windows平台下开发用的一些比较好的软件-WinSCP(四)

2016-03-1116:47:00 发表评论 722℃热度 WinSCP 它是一个Windows环境下使用SSH的开源图形化SFTP客户端。同时支持SCP协...

3097
来自专栏派森公园

docker的reap问题

在使用docker容器的时候,应该了解“PID1僵尸进程reap”问题。如果使用的时候不加注意,可能会导致出现一些意想不到的问题。

1373
来自专栏進无尽的文章

扒虫篇-Bug日志 Ⅲ

解决方法:可能是由于粘贴网页上的代码的时候两行之间的回车引起的,有未识别的回车或者换行,找到,删除掉就 OK了。

1462
来自专栏跟着阿笨一起玩NET

asp.net中为什么修改了配置文件后我们不需要重启IIS

本文转载:http://blog.itpub.net/12639172/viewspace-659819/

3451

扫码关注云+社区

领取腾讯云代金券