You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用sigwait()/sigwaitinfo()等待信号终止可执行程序?

主线程休眠等待外部终止的实现方案

需要响应的信号

你需要关注以下几种常见的进程终止信号,这些是外部触发进程终止的主要方式:

  • SIGINT:用户在终端按下Ctrl+C时发送,属于交互式终止请求
  • SIGTERM:kill命令默认发送的信号,是系统或脚本中最常用的进程终止指令
  • SIGQUIT:用户按下Ctrl+\时发送,默认会生成核心转储文件(可通过配置关闭)
  • SIGHUP:终端会话断开时发送(比如SSH连接关闭),常用于通知后台进程重新配置或终止

具体实现步骤

使用sigwait()或sigwaitinfo()的核心逻辑是:先将目标信号阻塞(避免被系统默认处理直接终止进程),然后让主线程阻塞等待这些信号的到来,收到信号后执行清理并退出。

  1. 初始化信号集:创建一个sigset_t集合,将需要监听的信号添加进去
  2. 阻塞目标信号:通过sigprocmask()将信号集加入线程的信号掩码,确保这些信号不会被默认处理
  3. 等待信号:调用sigwait()或sigwaitinfo()阻塞主线程,直到收到目标信号
  4. 处理与退出:收到信号后执行必要的清理操作,然后正常退出进程

完整代码示例

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 02:37:01