温馨提示×

linux c++怎么处理信号

小樊
62
2026-07-05 19:07:09
栏目: 编程语言

在 Linux 下用 C++ 处理信号(signal),常见做法有 signal()sigaction(),以及更高级的 signalfd / self-pipe 等方式。下面按“从简单到推荐”给你一个完整说明。


一、什么是信号(signal)

信号是 Linux 中进程间异步通信的一种方式,例如:

信号 含义
SIGINT Ctrl+C
SIGTERM kill 默认信号
SIGKILL 不可捕获
SIGSEGV 段错误
SIGPIPE 管道破裂
SIGCHLD 子进程状态变化

二、最简单方式:signal()(不推荐)

#include <iostream>
#include <csignal>

void handler(int sig) {
    std::cout << "catch signal: " << sig << std::endl;
}

int main() {
    signal(SIGINT, handler);

    while (true) {}
}

缺点

  • 行为在不同 UNIX 系统不一致
  • 不可靠(可能被中断、重置)
  • 不推荐在新代码中使用

三、推荐方式:sigaction()(标准做法)

示例:捕获 SIGINT 和 SIGTERM

#include <iostream>
#include <csignal>
#include <unistd.h>

void signal_handler(int sig) {
    if (sig == SIGINT) {
        std::cout << "Caught SIGINT" << std::endl;
    } else if (sig == SIGTERM) {
        std::cout << "Caught SIGTERM, exiting..." << std::endl;
        _exit(0);
    }
}

int main() {
    struct sigaction sa{};
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    sigaction(SIGINT, &sa, nullptr);
    sigaction(SIGTERM, &sa, nullptr);

    while (true) {
        pause();  // 等待信号
    }
}

优点

✅ 可移植
✅ 行为明确
✅ 可屏蔽其他信号


四、信号处理中的注意事项(非常重要)

❌ 不要在信号处理函数中做这些事

  • malloc / free
  • cout << ...(不是 async-signal-safe)
  • 创建线程
  • 调用非 async-signal-safe 的函数

信号处理函数应只做“最小操作”


五、推荐模式:用 volatile sig_atomic_t

#include <csignal>
#include <iostream>
#include <unistd.h>

volatile sig_atomic_t g_running = 1;

void handler(int) {
    g_running = 0;
}

int main() {
    struct sigaction sa{};
    sa.sa_handler = handler;
    sigaction(SIGINT, &sa, nullptr);

    while (g_running) {
        // 主循环
        sleep(1);
    }

    std::cout << "exit cleanly" << std::endl;
}

✅ 安全
✅ 简单
✅ 常用于服务器程序


六、高级方式(推荐用于大型程序)

1️⃣ signalfd(Linux 特有)

把信号转成文件描述符,可配合 epoll

#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <iostream>

int main() {
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);

    sigprocmask(SIG_BLOCK, &mask, nullptr);

    int sfd = signalfd(-1, &mask, 0);
    while (true) {
        struct signalfd_siginfo si;
        read(sfd, &si, sizeof(si));
        std::cout << "Got signal: " << si.ssi_signo << std::endl;
    }
}

✅ 适合事件驱动程序
✅ 无信号处理函数限制


2️⃣ self-pipe 技巧(跨平台)

  • 信号处理函数写 pipe
  • 主循环读 pipe

(如果你需要我可以给示例)


七、常见信号对照表

信号 是否可捕获
SIGINT
SIGTERM
SIGKILL
SIGSTOP
SIGSEGV ✅(调试用)
SIGPIPE ✅(通常忽略)

八、总结建议

新代码用 sigaction()
信号处理函数只设标志
服务器程序用 signalfd + epoll
不用 signal()


如果你愿意,可以告诉我:

  • 普通程序 / 服务器 / 多线程程序
  • 是否需要 优雅退出 / 热重启

我可以给你一个生产级模板

0