

























C语言开发中有下面这四种的退出程序的方法
1、Ctrl + C → 发送 SIGINT 信号
2、kill 进程PID(不带参数)→ 发送 SIGTERM
3、kill -9 不执行任何清理
4、systemctl stop 停止服务 → 底层也是发送 SIGTERM
注:其中kill -9 是不执行任何清理的,所有在正常情况下不要使用
三种关闭操作对应的信号
1、Ctrl + C → 发送 SIGINT 信号
2、kill 进程PID(不带参数)→ 发送 SIGTERM
3、systemctl stop 停止服务 → 底层也是发送 SIGTERM
C 语言进程收到这两个信号,默认处理动作:立刻终止程序。
注意事项(生产环境必看)
信号处理函数内不能调用大量 IO / 复杂函数
ExitSys 内部需要主动关闭线程、zmq 上下文、释放硬件资源,否则会资源泄漏。
systemd 服务超时问题
如果 ExitSys 执行耗时较长(超过 systemd 默认 90 秒),服务会被强制发 SIGKILL(无法捕获,直接强杀)。
解决方案:
systemd 配置添加 TimeoutStopSec=120 延长停止等待时间;
ExitSys 内部所有关闭操作尽量缩短耗时。
kill -9 PID 无法捕获
任何代码都拦不住,进程瞬间销毁,不会执行任何清理,运维尽量不要用 kill -9。
实现原理
添加 SIGINT/SIGTERM 信号捕获 + 全局退出标记:
收到信号→标记置 1→while 循环结束→顺序执行 ExitSys、关闭日志,实现优雅退出程序
代码
主程序文件 ShPbxServer.c
#include <signal.h> //退出信号
/*====================== 主函数 ======================*/ int main(void) { // 重定向 stderr 以屏蔽 HMP 驱动的警告输出 (如 timer lost) //freopen("/dev/null", "w", stderr); //写这句退出信号就不能被补获到ExitSys()不能被执行 sigset_t wait_sigset; siginfo_t sig_info; struct timespec zero_ts = {0, 0}; int caught_sig; // 阻塞SIGINT/SIGTERM,子线程全部继承屏蔽,信号只留在主线程 sigemptyset(&wait_sigset); sigaddset(&wait_sigset, SIGINT); sigaddset(&wait_sigset, SIGTERM); pthread_sigmask(SIG_BLOCK, &wait_sigset, NULL); // 仅屏蔽管道破裂信号,不处理退出信号 signal(SIGPIPE, SIG_IGN); // 初始化日志 Log_Init(); Log_Write("======================================="); Log_Write("======== ShPbxServer v1.8 启动 ========"); Log_Write("======================================="); if (InitSys() != 0) { Log_Write("[ShPbxServer][错误] 系统初始化失败"); Log_Close(); return -1; } Log_Write("[ShPbxServer][信息] 系统初始化成功,通道数:%d", nTotCh); // ===================== 服务后台专用死循环(不退出、不阻塞、不占CPU) ===================== //// 后台循环:只做非阻塞业务,不阻塞等待信号 while (1) {// 后台死循环,微小sleep降低CPU,同时保证信号标记生效 //sleep(1); // 每秒休眠一次,程序保持运行 usleep(500000); // 500ms,比sleep(1)响应更快 // 非阻塞检测是否收到退出信号 // 正确传参:第二个参数 &sig_info 匹配 siginfo_t* caught_sig = sigtimedwait(&wait_sigset, &sig_info, &zero_ts); if (caught_sig > 0) { break; } } Log_Write("[ShPbxServer][信息] 收到停止信号,准备优雅退出..."); ExitSys(); Log_Close();// 关闭日志 return 0; }
/*====================== 系统退出 ======================*/ void ExitSys(void) { //Log_Write("[ShPbxServer][信息] 正在关闭系统..."); // 1. 先关闭ZeroMQ(内部等待服务线程退出) Zmq_Cleanup(); Log_Write("[ShPbxServer][信息] ZeroMQ 服务已关闭"); // 2. 关闭音频推送ZeroMQ ZeroMQAudio_Cleanup(); Log_Write("[ShPbxServer][信息] 音频流推送服务已关闭"); // 3. 停止定时器线程 if (bSetTime == 1) { KillTimer(Th); Log_Write("[ShPbxServer][信息] Timer定时器已停止"); } // 4. 关闭CTI硬件,停止所有异步回调线程 Api_SsmCloseCti(); Log_Write("[ShPbxServer][信息] CTI 系统已关闭板卡SsmCloseCti()"); usleep(200000); // 延长等待,让回调函数全部执行完毕退出 // 最后销毁互斥锁 pthread_mutex_destroy(&g_TrkChMutex); }
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。