0

0

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

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-01-25 13:28:39

|

352人浏览过

|

来源于php中文网

原创

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 这类标志位,把信号处理降级为“设标志”,其余逻辑放在正常线程流中执行。

相关专题

更多
java中break的作用
java中break的作用

本专题整合了java中break的用法教程,阅读专题下面的文章了解更多详细内容。

118

2025.10.15

java break和continue
java break和continue

本专题整合了java break和continue的区别相关内容,阅读专题下面的文章了解更多详细内容。

256

2025.10.24

java中break的作用
java中break的作用

本专题整合了java中break的用法教程,阅读专题下面的文章了解更多详细内容。

118

2025.10.15

java break和continue
java break和continue

本专题整合了java break和continue的区别相关内容,阅读专题下面的文章了解更多详细内容。

256

2025.10.24

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

482

2023.08.10

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

689

2023.07.26

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1127

2023.07.27

windows照片无法显示
windows照片无法显示

当我们尝试打开一张图片时,可能会出现一个错误提示,提示说"Windows照片查看器无法显示此图片,因为计算机上的可用内存不足",本专题为大家提供windows照片无法显示相关的文章,帮助大家解决该问题。

799

2023.08.01

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

41

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.7万人学习

Git 教程
Git 教程

共21课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号