C++ 怎么捕获Ctrl+C C++ signal处理中断信号【控制台】

Ctrl+C在Windows和Linux上均触发SIGINT信号,但处理机制不同:Linux/macOS推荐sigaction(),Windows应使用SetConsoleCtrlHandler(),跨平台需统一通过轮询原子标志位实现。

c++ 怎么捕获ctrl+c c++ signal处理中断信号【控制台】

Ctrl+C 在 Windows 和 Linux 上都触发 SIGINT

终端按下 Ctrl+C 时,操作系统会向当前前台进程发送 SIGINT 信号,不是 C++ 语言特性,而是 POSIX(Linux/macOS)和 Windows CRT(如 MSVC 运行时)都支持的通用机制。关键区别在于:Linux 默认终止进程,Windows 控制台默认也终止,但两者都允许你注册处理函数来拦截它。

用 signal() 注册简单处理函数,但有严重限制

signal() 是最基础的方式,适合快速响应、不涉及复杂逻辑的场景。但它在信号处理期间禁止调用大部分标准库函数(如 std::coutmalloc),且不能保证重入安全。常见错误是直接在里面打印日志或调用 std::exit() —— 这可能崩溃或死锁。

  • 只允许调用异步信号安全函数(如 write()_exit()
  • 不要在 handler 中修改全局对象、调用 STL 容器方法或抛异常
  • MSVC 的 signal() 在 Windows 上对 SIGINT 支持较稳定;GCC/Clang 下推荐用 sigaction()(见下条)

示例(仅用于演示,不推荐生产):

#include 
#include 

volatile std::sig_atomic_t g_stop_requested = 0;

void signal_handler(int sig) {
    if (sig == SIGINT) {
        g_stop_requested = 1; // OK: sig_atomic_t 是原子读写类型
    }
}

int main() {
    std::signal(SIGINT, signal_handler);
    while (!g_stop_requested) {
        // 做工作...
    }
    std::cout << "Exiting gracefully./n";
}

用 sigaction() 更可靠(Linux/macOS 推荐)

sigaction() 提供更细粒度控制:可屏蔽其他信号、指定是否重启被中断的系统调用、避免信号处理函数被多次触发等。它不修改全局状态,行为可预测,是 POSIX 系统首选。

立即学习C++免费学习笔记(深入)”;

Originality AI

Originality AI

专门为网络出版商设计的抄袭和AI检测工具

下载

  • 必须用 struct sigaction 显式配置,不能像 signal() 那样传函数指针就完事
  • 设置 sa_flags |= SA_RESTART 可让阻塞式系统调用(如 read())在收到信号后自动重试,而不是返回 -1 + EINTR
  • sigfillset(&act.sa_mask) 可临时屏蔽所有信号,防止嵌套中断

注意:sigaction() 在 Windows MinGW 环境可用,但原生 MSVC 不支持 —— 如果跨平台,需条件编译。

Windows 控制台专用:SetConsoleCtrlHandler()

Windows 提供了比 signal() 更底层、更可控的 API:SetConsoleCtrlHandler()。它能捕获 CTRL_C_EVENTCTRL_BREAK_EVENT、甚至关机前的 CTRL_SHUTDOWN_EVENT,且 handler 中可以安全调用多数 Win32 API(比如 SetEvent()PostThreadMessage())。

  • handler 函数必须是 BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType) 类型
  • 返回 TRUE 表示已处理,系统不再执行默认动作(即不退出);返回 FALSE 则继续传递给下一个 handler 或执行默认终止
  • 不能在 handler 中调用 ExitProcess()TerminateProcess(),否则会导致未定义行为

这是 Windows 下唯一能可靠响应 Ctrl+Break 或关机通知的方式,signal() 对后者完全无效。

真正麻烦的是跨平台统一处理:SIGINT 语义在不同系统上看似一致,但底层机制、线程安全性、可调用函数集差异极大。别试图写一个“通用 handler 函数”,应该按平台分路径,在主循环里轮询 g_stop_requested 这类标志位,把信号处理降级为“设标志”,其余逻辑放在正常线程流中执行。

https://www.php.cn/faq/2028881.html

发表回复

Your email address will not be published. Required fields are marked *