sigint是编号为2的用户中断信号,用于在按下ctrl+c时通知前台进程安全收尾而非强制终止;需通过sigaction()注册处理函数,仅设volatile标志位,主循环检查该标志并执行清理后退出。

SIGINT 是 Linux 中最常用的用户中断信号,编号为 2,本质是“让程序响应 Ctrl+C 并安全收尾”,而不是粗暴杀死。关键不在于“发信号”,而在于进程能否在收到后释放资源、保存状态、再退出——这才是“安全中断”的核心。
理解 SIGINT 的触发与默认行为
按下 Ctrl+C 时,终端会向当前前台进程发送 SIGINT;它不是强制终止(那是 SIGKILL),而是给程序一次“主动收手”的机会。默认情况下,进程会立即退出,但不会执行清理动作——比如没关闭打开的文件、没刷新缓冲区、没释放锁或网络连接,就可能造成数据损坏或资源泄漏。
- 信号只通知事件发生,不传递任何数据
- 它异步到达,可能在任意代码位置被递送
- 不能被阻塞或忽略的信号只有 SIGKILL 和 SIGSTOP;SIGINT 可捕获、可忽略、也可自定义处理
用 signal() 或 sigaction() 捕获并处理 SIGINT
要实现安全中断,必须显式注册信号处理函数。推荐使用 sigaction()(比 signal() 更可靠,避免竞态和重入问题):
- 声明一个处理函数,例如
void handle_int(int sig) - 用
sigaction()绑定该函数到 SIGINT,并设置SA_RESTART(避免系统调用被中断后不自动重试) - 在处理函数中:设标志位(如全局 volatile int running = 1)、关闭文件描述符、写入临时进度、释放内存等
- 主循环需定期检查标志位,主动退出,而非在信号处理函数里直接调用 exit() 或 longjmp()
避免常见陷阱
信号处理函数是受限环境,很多操作不安全:
- 不要在 handler 里调用 printf、malloc、free、open 等非异步信号安全函数(async-signal-safe)
- 不要从 handler 返回后继续执行原逻辑——应通过标志位控制主流程退出
- 不要假设信号只来一次:多次 Ctrl+C 可能导致重复调用 handler,需确保处理逻辑幂等
- 多线程程序中,SIGINT 默认只发给主线程;如需指定接收线程,要用 pthread_sigmask() 屏蔽并定向投递
实际场景中的典型做法
以一个下载工具为例:
- 启动时注册 SIGINT 处理器,设置
volatile sig_atomic_t interrupted = 0 - 每次写入文件前检查
if (interrupted) { flush_buffer(); close(fd); exit(0); } - handler 中仅做
interrupted = 1;——简洁、安全、无副作用 - 若支持断点续传,可在 handler 触发后写入当前已下载字节数到临时文件











