kill命令本质是向进程发送信号,不只用于终止;默认发SIGTERM(15)请求优雅退出,也可发SIGHUP(1)重载配置、SIGSTOP(19)挂起、SIGCONT(18)恢复等,响应方式由进程自身决定。

kill 命令怎么发信号给进程(不是终止)
Linux 的 kill 命令默认发的是 SIGTERM(15 号信号),但它本身不只用于“杀死”进程——它本质是发送任意信号的工具。想让进程重载配置、暂停、继续或退出,都靠它。
常见误区是以为 kill 一定等于强制结束;实际上,是否响应、如何响应,完全由目标进程自己决定。
- 发
SIGHUP(1):常用于通知服务重读配置文件,比如kill -HUP <code>pid - 发
SIGSTOP(19):挂起进程(不可被忽略),类似 Ctrl+Z 效果 - 发
SIGCONT(18):恢复被挂起的进程 - 发
SIGUSR1/SIGUSR2(10/12):自定义用途,需进程主动处理
怎么查进程 PID 和当前信号处理方式
没 PID 就没法发信号。别依赖 ps aux | grep xxx 手动找,容易误杀同名进程。
- 用
pgrep -f "your_command"精准匹配命令行参数 - 用
pidof your_binary_name(要求进程名与可执行文件名一致) - 看进程对信号的响应:运行
cat /proc/<code>pid/status | grep Sig,SigCgt字段是十六进制掩码,表示已注册 handler 的信号(需查表转换)
更实用的办法是先试发 SIGUSR1 并观察日志或行为变化,确认进程是否监听该信号。
立即学习“C++免费学习笔记(深入)”;
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
C++ 进程里怎么安全接收并处理 kill 发来的信号
直接用 signal() 不可靠,尤其在多线程下;必须用 sigaction() 配合 sigprocmask() 控制信号屏蔽。
-
signal()在不同系统上语义不一致,POSIX 明确推荐避免使用 -
sigaction()支持设置SA_RESTART(自动重启被中断的系统调用)、SA_NODEFER(不自动屏蔽本信号)等关键标志 - 不要在 signal handler 里调用
printf、malloc、std::cout—— 它们不是 async-signal-safe - 安全做法:handler 中只写一个
volatile sig_atomic_t标志,主循环定期检查并做实际处理
示例片段:
volatile sig_atomic_t g_reload_requested = 0;
void handle_hup(int) { g_reload_requested = 1; }
// ...
struct sigaction sa = {};
sa.sa_handler = handle_hup;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGHUP, &sa, nullptr);
// 主循环中:
if (g_reload_requested) {
reload_config(); // 这里才做真正工作
g_reload_requested = 0;
}
为什么 kill -9 后进程还存在(或立刻消失但没清理资源)
kill -9 即 SIGKILL,内核强制终止进程,无法被捕获、阻塞或忽略。它快,但也粗暴。
- 不会调用 C++ 对象析构函数(
~MyClass()不执行) - 不会执行
atexit()注册的函数 - 不会释放 mmap 映射、关闭 fd(由内核回收,但应用层逻辑可能丢失状态)
- 如果进程正在写文件且没 flush,可能留下损坏数据
所以日常运维优先用 kill(SIGTERM),等几秒再 kill -9;写 C++ 服务时,务必在 SIGTERM handler 中完成资源清理和优雅退出逻辑。
信号处理最易被忽略的点:子进程继承父进程的信号处理设置,但 fork 后若没重置,可能导致子进程意外响应父进程的信号。fork 之后、exec 之前,建议用 sigprocmask() 清空信号掩码或显式重设 handler。

















