如何用C语言实现响应SIGTERM生成子进程的可靠守护进程?
解决SIGTERM触发后子进程退出或无法接收信号的问题
先给你修正后的可运行代码,能实现你要的功能:收到SIGTERM就fork子进程,父进程退出,子进程继续监听信号,循环往复:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> static void handler(int signum) { if (signum == SIGTERM) { pid_t pid = fork(); if (pid < 0) { perror("Fork failed"); exit(EXIT_FAILURE); } if (pid > 0) { // 父进程直接退出 exit(EXIT_SUCCESS); } // 子进程重新配置信号处理(确保可靠) struct sigaction sa; sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; // 让被信号中断的系统调用自动重启 if (sigaction(SIGTERM, &sa, NULL) == -1) { perror("sigaction failed"); exit(EXIT_FAILURE); } printf("Child process created (PID: %d)\n", getpid()); } } int main(void) { // 第一次fork创建守护进程,脱离父进程 pid_t pid = fork(); if (pid < 0) { perror("Fork failed"); exit(EXIT_FAILURE); } if (pid > 0) { exit(EXIT_SUCCESS); } // 配置SIGTERM的可靠信号处理 struct sigaction sa; sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGTERM, &sa, NULL) == -1) { perror("sigaction failed"); exit(EXIT_FAILURE); } printf("Daemon started (PID: %d)\n", getpid()); // 主循环保持进程存活 while (1) { sleep(1); } return EXIT_SUCCESS; }
为啥你原来的代码有问题?
第一个版本子进程退出:
你用的signal()函数是老式实现,信号触发一次后,系统会自动把信号处理重置为默认动作(SIGTERM默认是终止进程)。子进程从处理函数返回后,虽然回到主循环,但此时SIGTERM的处理已经变回默认,再发信号直接就会被终止。另外sleep()被信号中断后会提前返回,但主循环本来能继续,只是信号处理没了导致后续无法响应。第二个版本子进程收不到信号:
你在信号处理函数里加了无限循环,进程会一直卡在处理函数里,根本回不到主循环。而且信号处理期间,同类型信号会被阻塞,就算重新注册也没用——进程都没机会处理新信号。
关键修复点
- 用
sigaction()代替signal():这是POSIX标准的可靠信号处理,不会自动重置处理函数,还能通过参数控制行为。 - 加
SA_RESTART标志:让sleep()这种被信号中断的系统调用自动重启,避免主循环因为sleep()返回错误而意外退出。 - 信号处理函数别搞复杂:只做fork和必要配置,然后返回,让进程回到主循环继续监听,别在处理函数里写循环。
内容的提问来源于stack exchange,提问作者Íñigo Aldaraborda
相关产品推荐
相关产品推荐

