bigywater.tech
Rust · 144

信号处理

服务收到 SIGTERM 时怎么「优雅退出」?为什么 Drop 有时不运行?信号会排队吗?哪些信号不能捕获?这篇用真实的子进程和 libc 的 sigaction 逐条验证。

-15
没有处理函数时 SIGTERM 终止进程的退出码(被信号 15 终止)
100 → 1
阻塞期间发 100 个 SIGUSR1,解除阻塞后处理函数的调用次数
EINVAL
对 SIGKILL 安装处理函数的错误

默认行为

实测 · 本机执行输出
  编译:成功
  子进程输出: ['子进程开始等待(pid 55836),等 SIGTERM']
  收到 SIGTERM 后:退出码 -15(负数 = 被信号 15 终止),没有 "Guard 被 drop" 这一行

进程启动与 SIGPIPE 见Rust 二进制启动过程;Drop 见Drop Trait 与资源释放。

优雅退出

实测 · 本机执行输出
  编译:成功
  子进程输出:
    installed sigaction,返回 0
      工作中(pid 55850),等待 SIGTERM
      发现停止标志,处理函数被调用 1 次,退出主循环
      Guard(优雅退出) 被 drop —— 清理代码运行了
  退出码 0

signal-hook、ctrlc 等 crate 把这个模式封装成安全接口,本文用的是直接的 libc 调用。

信号会合并

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      不阻塞:连续发 100 次,处理函数被调用 100 次
      阻塞期间发 100 次,解除阻塞前处理函数被调用 0 次
      解除阻塞后:处理函数共被调用 1 次(100 个信号被合并成 1 个待处理信号)

SIGKILL

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      对 SIGKILL 安装处理函数:返回 -1;对 SIGTERM:返回 0
      errno = Some(22)

当前的处理方式

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      SIGPIPE  当前处理:SIG_IGN(忽略)
      SIGINT   当前处理:SIG_DFL(默认)
      SIGTERM  当前处理:SIG_DFL(默认)
      SIGUSR1  当前处理:SIG_DFL(默认)

子进程的发送与等待见子进程与 Command。

分步演示

信号处理
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。macOS(信号编号 SIGUSR1 = 30,Linux 上是 10)
    • 没有验证:在处理函数里调用 println! 或分配内存的后果(不是 async-signal-safe,按惯例避免)、多线程下信号由哪个线程处理、SA_RESTART 与被中断的系统调用(EINTR)、signal-hook crate 的行为、Windows 的 Ctrl-C 处理
    京ICP备2026067502号-1京公网安备11010502063487号