原文地址:优雅关闭进程 – 无敌牛
欢迎参观我的个人博客:无敌牛 – 技术/著作/典籍/分享等
介绍
本文涉及到进程对信号的响应,关于信号的一些基本知识,可以参考往期文章:linux系统信号简介 – 无敌牛
一个进程正常运行的时候,可以通过给进程发送 SIGKILL 9 信号,直接强制关闭进程。进程所持有的一些资源,由操作系统来回收处理,这样确实很省事。但是这种做法也很暴力,会导致一些资源不能及时释放。例如监听端口、需要清理的 PID 文件等等。那么怎么优雅地关闭一个正在运行的进程呢?
这就需要给进程设置信号响应。SIGKILL 信号始终都可以强制关闭进程,这是因为 SIGKILL 信号是不可被捕捉,也就不可以被进程重新设置信号处理函数。但是有另外两个信号 SIGINT 2 和 SIGTERM 15 是可以被捕捉的,也经常用来优雅地关闭进程。我们可以让进程捕捉这两个信号,然后设置信号处理函数,来主动释放进程所持有的资源,让进程自动退出。
另外 systemctl stop xxx 就是给进程发送 SIGTERM 信号,让进程主动退出。
示例
以下以 python 为例,结合 systemd 启停 python 进程来测试的。其中还涉及 python 的虚拟环境,可以参考往期文章:python虚拟环境 – 无敌牛
当然也可以直接发送 2 和 15 信号让进程自动关闭。执行指令:kill -2 pid 和 kill -15 pid 就可以了。
如果要 C 语言实现,也是同样的道理,捕捉信号,设置信号处理函数,主动退出。
代码 tsys.py
import signal
import time
from pid import PidFile# 服务运行状态,为 True 就需要主动释放一些资源了
exit_flag = Falsedef stop_handler(sig, frame) :global exit_flag# 设置进程为待关闭状态exit_flag = Trueprint("get "+signal.strsignal(sig)+" "+str(sig), flush=True)# 启动自己的服务
def run_server() :while True:# 判断是否接收到中断服务的信号if exit_flag :## 等待未完成的服务处理完## 回收资源,关闭文件描述符等等break## 在这里运行自己需要的服务,申请资源等等print("still running", flush=True)time.sleep(1)passif __name__ == "__main__" :# 响应 SIGINT 2 中断信号signal.signal( signal.SIGINT, stop_handler )# 响应 SIGTERM 15 请求进程终止信号signal.signal( signal.SIGTERM, stop_handler )with PidFile(pidname="tsys.pid", piddir=".") :run_server()
配置 tsys.service,路径 /usr/lib/systemd/system/tsys.service
[Unit]
Description=Test pid file SIGTERM
After=multi-user.target[Service]
Type=simple
WorkingDirectory=/root/test
ExecStart=bash -c "source /opt/tvenv/bin/activate && exec python tsys.py > tsys.log"
Restart=always[Install]
WantedBy=multi-user.target
测试
启动
停止