如何用sigwait()/sigwaitinfo()等待信号终止可执行程序?
主线程休眠等待外部终止的实现方案
需要响应的信号
你需要关注以下几种常见的进程终止信号,这些是外部触发进程终止的主要方式:
- SIGINT:用户在终端按下
Ctrl+C时发送,属于交互式终止请求 - SIGTERM:
kill命令默认发送的信号,是系统或脚本中最常用的进程终止指令 - SIGQUIT:用户按下
Ctrl+\时发送,默认会生成核心转储文件(可通过配置关闭) - SIGHUP:终端会话断开时发送(比如SSH连接关闭),常用于通知后台进程重新配置或终止
具体实现步骤
使用sigwait()或sigwaitinfo()的核心逻辑是:先将目标信号阻塞(避免被系统默认处理直接终止进程),然后让主线程阻塞等待这些信号的到来,收到信号后执行清理并退出。
- 初始化信号集:创建一个
sigset_t集合,将需要监听的信号添加进去 - 阻塞目标信号:通过
sigprocmask()将信号集加入线程的信号掩码,确保这些信号不会被默认处理 - 等待信号:调用
sigwait()或sigwaitinfo()阻塞主线程,直到收到目标信号 - 处理与退出:收到信号后执行必要的清理操作,然后正常退出进程
完整代码示例
使用sigwait()的基础实现
#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> int main() { sigset_t wait_set; int received_sig; // 初始化信号集并添加需要监听的信号 sigemptyset(&wait_set); sigaddset(&wait_set, SIGINT); sigaddset(&wait_set, SIGTERM); sigaddset(&wait_set, SIGQUIT); sigaddset(&wait_set, SIGHUP); // 阻塞信号,防止默认处理逻辑触发 if (sigprocmask(SIG_BLOCK, &wait_set, NULL) == -1) { perror("sigprocmask failed"); exit(EXIT_FAILURE); } printf("Main thread waiting for termination signals...\n"); printf("PID: %d | Use Ctrl+C, Ctrl+\\, or 'kill %d' to terminate\n", getpid(), getpid()); // 阻塞等待信号 if (sigwait(&wait_set, &received_sig) == -1) { perror("sigwait failed"); exit(EXIT_FAILURE); } // 打印收到的信号 switch (received_sig) { case SIGINT: printf("\nReceived SIGINT (Ctrl+C)\n"); break; case SIGTERM: printf("\nReceived SIGTERM\n"); break; case SIGQUIT: printf("\nReceived SIGQUIT (Ctrl+\\)\n"); break; case SIGHUP: printf("\nReceived SIGHUP\n"); break; default: printf("\nReceived unexpected signal: %d\n", received_sig); } // 执行清理操作(示例:关闭文件、释放内存等) printf("Running cleanup tasks...\n"); exit(EXIT_SUCCESS); }
使用sigwaitinfo()获取更多信号细节
如果需要获取信号的附加信息(比如发送信号的进程ID),可以用sigwaitinfo()替代sigwait():
#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> int main() { sigset_t wait_set; siginfo_t sig_info; sigemptyset(&wait_set); sigaddset(&wait_set, SIGINT); sigaddset(&wait_set, SIGTERM); if (sigprocmask(SIG_BLOCK, &wait_set, NULL) == -1) { perror("sigprocmask failed"); exit(EXIT_FAILURE); } printf("Waiting for signals... PID: %d\n", getpid()); // 等待并获取信号详情 if (sigwaitinfo(&wait_set, &sig_info) == -1) { perror("sigwaitinfo failed"); exit(EXIT_FAILURE); } printf("Received signal %d from process %d\n", sig_info.si_signo, sig_info.si_pid); printf("Cleanup done. Exiting.\n"); exit(EXIT_SUCCESS); }
关键注意事项
- 必须先阻塞目标信号:如果信号没有被阻塞,调用
sigwait()前信号可能已经触发默认处理(直接终止进程),导致sigwait()永远不会被执行 - 多线程场景下:所有线程都应该阻塞目标信号,避免其他线程收到信号触发默认处理;
sigwait()只能在一个线程中调用等待 - 信号处理的原子性:
sigwait()是原子操作,不会出现信号丢失的情况
内容的提问来源于stack exchange,提问作者zombieanfuehrer
相关产品推荐
相关产品推荐

