Debian 10下如何捕获系统关机事件以实现数据持久化?
解决Debian 10系统关机前无法捕获事件保存数据的问题
问题分析
你的代码存在两个关键问题:
- 同时混用
sigaction和signal注册SIGTERM信号处理函数,后者会覆盖前者设置,导致信号处理逻辑混乱 proc_term仅设置退出标志,未执行实际的数据保存操作;且信号处理函数内调用的LOG_WARN如果是非异步安全函数,可能引发未定义行为
修复方案
1. 统一使用sigaction注册信号
放弃signal函数,用sigaction统一处理所有需要捕获的信号(系统关机时通常发送SIGTERM,终端中断发送SIGINT,部分场景还会发送SIGHUP):
#include <signal.h> #include <string.h> #include <unistd.h> volatile sig_atomic_t need_exit = 0; void handle_signal(int sig) { // 使用异步安全的方式记录信号,避免调用非安全函数 const char *msg; switch(sig) { case SIGTERM: msg = "Received SIGTERM (shutdown/terminate)\n"; break; case SIGINT: msg = "Received SIGINT (interrupt)\n"; break; case SIGHUP: msg = "Received SIGHUP (hangup)\n"; break; default: msg = "Received unknown signal\n"; break; } // write是异步安全函数,直接写入标准错误输出 write(STDERR_FILENO, msg, strlen(msg)); need_exit = 1; } void setup_signals() { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = handle_signal; // 阻塞所有信号,避免处理信号时被其他信号打断 sigfillset(&sa.sa_mask); // 注册需要捕获的信号 sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGHUP, &sa, NULL); }
2. 主程序检测退出标志并执行保存
在主循环中定期检查need_exit标志,一旦触发就执行数据保存并退出:
#include <unistd.h> // 假设你有这个数据保存函数,需保证逻辑同步、无副作用 void save_data_to_file(); int main() { setup_signals(); while(!need_exit) { // 你的业务逻辑代码 sleep(1); } // 执行数据保存操作 save_data_to_file(); return 0; }
3. systemd服务额外配置(若应用由systemd管理)
Debian 10默认使用systemd,若你的应用通过systemd管理,需修改服务文件(如/etc/systemd/system/your-app.service),确保systemd给足进程退出时间:
[Service] ExecStart=/path/to/your/application # 让systemd等待进程主动退出,而非直接强制杀死 KillMode=process # 设置关机时等待进程退出的超时时间(根据保存逻辑调整时长) TimeoutStopSec=30s # 禁止超时后发送SIGKILL,保证进程有机会完成保存 SendSIGKILL=no
修改后执行systemctl daemon-reload && systemctl restart your-app.service生效。
关键注意事项
- 信号处理函数必须是异步安全的:不能调用
malloc、printf、非异步安全的日志函数等,仅能使用POSIX定义的异步安全函数(如write、_exit等) - 数据保存函数要保证原子性,可先写入临时文件,完成后再替换目标文件,避免关机时写入一半导致文件损坏
内容的提问来源于stack exchange,提问作者user1234
相关产品推荐
相关产品推荐

