在C语言中仅捕获子进程终止场景下的SIGCHLD信号
仅通过SIGCHLD追踪子进程终止的实现方法
当然可以不用额外发送SIGUSR1信号,仅通过SIGCHLD就能精准追踪子进程的终止事件,这里有两种可靠的实现方式:
方法一:让父进程只在子进程终止时收到SIGCHLD
通过设置sigaction的SA_NOCLDSTOP标志,就能让系统仅在子进程终止(包括正常退出或被信号杀死)时向父进程发送SIGCHLD,子进程因SIGSTOP等信号停止时不会触发该信号。
示例代码:
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <sys/wait.h> #include <unistd.h> void sigchld_handler(int sig) { int status; pid_t pid; // 循环处理所有已终止的子进程,避免信号丢失(多个子进程可能同时终止) while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { if (WIFEXITED(status)) { printf("子进程 %d 正常终止,退出码:%d\n", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("子进程 %d 被信号 %d 终止\n", pid, WTERMSIG(status)); } } } int main() { struct sigaction sa; sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); // SA_NOCLDSTOP:子进程停止时不发送SIGCHLD;SA_RESTART:被信号中断的系统调用自动重启 sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(EXIT_FAILURE); } // 示例:创建子进程 pid_t child_pid = fork(); if (child_pid == 0) { sleep(2); exit(0); // 子进程正常终止 } else if (child_pid == -1) { perror("fork"); exit(EXIT_FAILURE); } pause(); // 等待信号 return 0; }
方法二:在SIGCHLD处理函数中判断子进程状态
如果需要保留子进程停止时的SIGCHLD信号触发(比如后续可能要处理停止事件),可以不设置SA_NOCLDSTOP,而是在信号处理函数中通过waitpid获取子进程状态,仅处理终止的情况,忽略停止事件。
示例代码:
void sigchld_handler(int sig) { int status; pid_t pid; // WUNTRACED:获取子进程停止的状态 while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { if (WIFEXITED(status)) { printf("子进程 %d 正常终止\n", pid); } else if (WIFSIGNALED(status)) { printf("子进程 %d 被信号终止\n", pid); } // WIFSTOPPED(status)的情况直接忽略,不做处理 } }
关键说明
- 使用
waitpid而非wait:waitpid支持非阻塞模式(WNOHANG),能一次性处理所有已终止的子进程,避免信号丢失;同时可以指定选项获取停止状态。 - 循环调用
waitpid:因为SIGCHLD信号是不可靠信号(可能多个子进程终止只触发一次信号),循环调用才能处理所有终止的子进程。
内容的提问来源于stack exchange,提问作者alexstamy
相关产品推荐
相关产品推荐

