Unix 让进程安全地退出
终止一个进程有很多方法(暂只说linux环境):前台运行的进程,如果没有提供退出功能,我们通常会Ctrl+C进行终止;后台或守护进程,如果也没有提供退出命令啥的,咱通常会kill掉;此外还有类似关机或重启之类的特殊情况,也会导致进程终止。
无论哪种方法,最终都是通过向进程传递信号量的方式进行终止。只是不同的方式发送的信号也不同:比如Ctrl+C发送的是SIGINT,kill和killall发送的是SIGTERM,kill -9发送的是SIGKILL,等等。
有些信号可以在程序中捕获,针对进行特殊处理;而有些则手动捕获不了或不能忽略,只能服从命令。
对于那些可以捕获到的终止类信号(如SIGTERM、SIGHUP、SIGINT等),就如同家长向正在玩仙剑的孩子说道:“玩儿一下午了,别玩了。”
如果碰到顽皮的,那么很可能就当作耳边风了——捕获到信号后选择不终止进程;
如果孩子还算听话,那么就赶紧把游戏存个档退出了——捕获到信号后做好收尾工作,然后终止进程(安全退出,推荐);
有的则图省事直接退出——不捕获信号或不做特殊处理,直接终止进程(大部分人都这么做,不推荐);
如果碰到的是个严厉的家长,二话不说直接上前把游戏关掉,这下孩子傻眼了“我擦,还没存档!!!”——接收到了不可被忽略的终止信号
另外还有一点需要注意,针对关机和重启的情况,是由操作系统按PID正序逐个发送SIGTERM,通知大家“做好准备,要关机了”,随后(n秒后)会下最后通谍——SIGKILL。对于子进程来说,父进程由于PID小,会先收到SIGTERM,收到后会立即向子进程发SIGKILL结束子进程。这样很可能会造成子进程接收不到操作系统发的SIGTERM,还未进行收尾工作就被终止。所以,还是尽量在主进程做收尾工作,或者主进程收到SIGTERM后主动向子进程发送SIGTERM(仅仅是这么想的,未验证 -.-)。
---------------------------------------------------分割线------------------------------------------------------------
附录:
网上的一段示例代码(Python)
#!/usr/bin/env python import time import signal import sys NEEDEXIT=False def SignalHandler(sig, id): global NEEDEXIT if sig == signal.SIGUSR1: print 'received signal USR1' elif sig == signal.SIGHUP: print 'received signal HUP' elif sig == signal.SIGTERM: print 'received SIGTERM, shutting down' NEEDEXIT = True signal.signal(signal.SIGUSR1, SignalHandler) signal.signal(signal.SIGHUP, SignalHandler) signal.signal(signal.SIGTERM, SignalHandler) while 1: if NEEDEXIT: sys.exit() time.sleep(1)