如何在Linux环境下的C++函数中避免中断?
问题
在Linux系统中运行长时间计算任务时,会定期保存部分计算结果。希望确保保存结果的函数不被中断——比如用户按下CTRL-C时,要让该函数执行完成后再终止程序。
示例代码如下,要求每次输出“Saving...”后必须输出“Done”:
#include <iostream> void save_result(int i) { disable_interruptions(); // 这里该写什么? std::cout << "Saving..."; /* 打开文件、根据i编辑内容等操作 */ std::cout << "Done\n"; enable_interruptions(); // 这里该写什么? } int main() { while(true) { int i = 1; /* 一些耗时的计算 */ save_result(i); } }
已尝试的方案:
- 利用文件原子性特性,但需要修改多个不同位置的文件,无法同时完成所有更新。
- 复制文件、编辑副本后原子性移回原位置,但文件体积过大,耗时太长。
解决方案
在Linux下,你可以通过信号掩码临时阻塞SIGINT信号(对应CTRL-C),让save_result执行期间不会被中断,完成后再恢复信号处理逻辑。
实现代码
#include <iostream> #include <signal.h> // 全局终止标志,用于优雅退出循环 static bool g_terminate = false; void save_result(int i) { sigset_t block_set, old_set; // 初始化信号集,添加需要阻塞的SIGINT sigemptyset(&block_set); sigaddset(&block_set, SIGINT); // 阻塞SIGINT,同时保存当前的信号掩码到old_set sigprocmask(SIG_BLOCK, &block_set, &old_set); std::cout << "Saving..."; /* 这里执行文件打开、编辑等保存操作 */ std::cout << "Done\n"; // 恢复原来的信号掩码,允许SIGINT再次触发 sigprocmask(SIG_SETMASK, &old_set, nullptr); } // SIGINT信号处理函数:提示用户并设置终止标志 void sigint_handler(int sig) { std::cout << "\n收到中断信号,将在当前保存完成后退出\n"; g_terminate = true; } int main() { // 注册SIGINT的自定义处理函数 struct sigaction sa; sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGINT, &sa, nullptr); while(!g_terminate) { int i = 1; /* 执行耗时计算 */ save_result(i); } std::cout << "程序已退出\n"; return 0; }
关键说明
sigprocmask的作用:SIG_BLOCK:将SIGINT加入当前阻塞信号集,临时屏蔽CTRL-C的触发。SIG_SETMASK:恢复之前保存的信号掩码,让SIGINT重新生效。
- 优雅退出逻辑:通过全局标志
g_terminate,让程序在收到中断信号后,完成当前保存操作再退出循环,避免强制终止。 - 注意事项:
- 不要让
save_result的阻塞阶段执行过长时间,否则用户按下CTRL-C后会出现短暂无响应。 - 如果需要屏蔽其他终止信号(如
SIGTERM),可以将其添加到block_set中。
- 不要让
内容的提问来源于stack exchange,提问作者Michele Borassi
相关产品推荐
相关产品推荐

