4.2.4 信号机制概述:信号分类与默认行为
信号(signal)是内核向进程发送的异步事件通知机制,用于告知进程发生了特定事件或请求其采取动作。信号既是进程间通信手段,也是内核控制进程的重要方式。每个信号都有编号、名称与默认行为,进程可选择捕获、忽略或使用默认处理方式(部分信号不可被捕获或忽略)。
原理草图:信号流转与默认行为#
信号分类#
- 致命类(Terminating):默认终止进程,常用于异常或结束指令,如
SIGTERM、SIGINT、SIGHUP。 - 致命并生成核心转储(Core Dump):默认终止并生成 core 文件,便于排查,如
SIGSEGV、SIGABRT、SIGFPE、SIGILL。 - 停止类(Stop):使进程暂停运行,需
SIGCONT恢复,如SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU。 - 继续类(Continue):使停止的进程继续运行,如
SIGCONT。 - 用户自定义类(User-defined):预留给应用自定义用途,如
SIGUSR1、SIGUSR2。
默认行为与可处理性#
- 可捕获/可忽略:大多数信号可通过处理函数或忽略改变默认行为。
- 不可捕获/不可忽略:
SIGKILL与SIGSTOP由内核强制执行,常用于无法被应用拦截的强制终止或停止。 - 默认行为可变:不同信号默认行为不同,应用应明确处理关键业务信号(如优雅退出、重载配置)。
常见信号与默认行为速览#
SIGTERM(15):请求终止,默认终止;适合优雅退出。SIGKILL(9):强制终止,不可捕获/忽略。SIGINT(2):终端中断(Ctrl+C),默认终止。SIGHUP(1):挂起/重载,默认终止,常用于重载配置。SIGQUIT(3):退出并生成 core。SIGSEGV(11):段错误,终止并生成 core。SIGABRT(6):异常终止,终止并生成 core。SIGSTOP(19):停止进程,不可捕获/忽略。SIGTSTP(20):终端停止(Ctrl+Z),可捕获/忽略。SIGCONT(18):继续进程运行。
命令示例:查看信号与发送信号#
# 1) 查看系统支持的信号列表
kill -l
# 2) 启动一个示例进程(占位)
sleep 300 &
echo "PID=$!"
# 3) 发送优雅终止信号
kill -TERM <PID>
# 4) 发送强制终止信号(仅在无响应时使用)
kill -KILL <PID>
命令解释
- kill -l:列出信号名称与编号。
- kill -TERM <PID>:发送 SIGTERM,应用可捕获做清理。
- kill -KILL <PID>:发送 SIGKILL,内核强制终止。
示例:模拟停止与继续#
# 启动进程
sleep 300 &
PID=$!
# 发送停止信号
kill -STOP $PID
# 查看进程状态,T 表示停止
ps -o pid,stat,cmd -p $PID
# 继续运行
kill -CONT $PID
示例:自定义信号处理(bash)#
# 文件: /tmp/signal_demo.sh
#!/usr/bin/env bash
trap 'echo "收到 SIGTERM,执行清理"; exit 0' TERM
trap 'echo "收到 SIGUSR1,执行自定义动作"' USR1
echo "PID=$$,运行中..."
while true; do
sleep 2
done
chmod +x /tmp/signal_demo.sh
/tmp/signal_demo.sh &
PID=$!
# 触发自定义信号
kill -USR1 $PID
# 优雅退出
kill -TERM $PID
运维视角要点#
- 优雅退出:优先使用
SIGTERM,便于应用释放资源、写入状态。 - 强制终止:仅在
SIGTERM无效时使用SIGKILL。 - 配置重载:许多服务将
SIGHUP作为重载信号。 - 诊断崩溃:core dump 类信号有助于定位程序缺陷。
排错清单#
- 信号未生效:确认 PID 正确、权限足够(非 root 无法操作他人进程)。
- 进程“无法杀死”:检查是否处于 D 状态(不可中断睡眠),需排查底层 I/O。
- 重载无效:确认服务是否支持
SIGHUP,必要时查看官方文档。 - core 不生成:检查
ulimit -c与core_pattern配置。
练习#
- 使用
sleep 300启动进程,分别发送SIGSTOP、SIGCONT,观察ps状态变化。 - 编写一个 trap 脚本捕获
SIGUSR1,并记录到日志文件中。 - 使用
kill -l查询SIGTSTP的编号,并用编号方式发送信号。