如何中断std::this_thread::sleep_for实现C++控制台程序快速优雅退出?
解决方案
标准C++的std::this_thread::sleep_for不支持主动中断,只有等待时长耗尽才会返回,因此你需要替换休眠逻辑来实现快速响应停止信号的需求,以下是两个适配你的Windows场景的可行方案:
方案1:使用Windows原生事件对象(Windows平台专属,实现最简单)
利用Windows的WaitForSingleObjectAPI,同时监听停止事件和超时逻辑,既能实现定时等待,也能在收到停止信号时立刻唤醒。
修改步骤:
- 新增全局停止事件对象,初始化时设为手动重置、初始未触发状态
- 在CtrlHandler中触发停止事件
- 替换
sleep_for为事件等待逻辑
#include <windows.h> #include <thread> #include <chrono> #include <vector> #include <atomic> std::atomic<bool> stopFlag = false; HANDLE g_hStopEvent; BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: stopFlag = true; SetEvent(g_hStopEvent); // 触发停止事件 return TRUE; default: return FALSE; } } void threadFn(int interval) { while (!stopFlag) { // 原有数据采集逻辑 // collect data and store in a vector // 替换原有sleep_for,等待停止事件或者超时 DWORD waitRet = WaitForSingleObject(g_hStopEvent, interval * 1000); // 单位转毫秒 if (waitRet == WAIT_OBJECT_0) { // 收到停止信号,直接退出循环 break; } // WAIT_TIMEOUT说明等待超时,继续下一轮循环 } // 原有数据统计输出逻辑 // accumulate vector values and display in the console } int main(int argc, char* argv[]) { SetConsoleCtrlHandler(CtrlHandler, TRUE); g_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 初始化停止事件 int interval = 10; // 示例间隔,可从用户输入获取 auto th = std::thread(threadFn, interval); if (th.joinable()) { th.join(); } CloseHandle(g_hStopEvent); // 释放事件资源 return 0; }
方案2:使用C++标准库条件变量(跨平台,适配Windows/Linux/macOS)
如果你需要代码具备跨平台能力,可以用std::condition_variable实现可中断的等待逻辑,不需要依赖平台原生API。
修改步骤:
- 定义全局条件变量、互斥锁和原子停止标记
- 在CtrlHandler中唤醒所有等待条件变量的线程
- 替换
sleep_for为条件变量的超时等待逻辑
#include <windows.h> #include <thread> #include <chrono> #include <vector> #include <condition_variable> #include <mutex> #include <atomic> std::atomic<bool> stopFlag = false; std::condition_variable g_cv; std::mutex g_mtx; BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: stopFlag = true; g_cv.notify_all(); // 唤醒所有等待的线程 return TRUE; default: return FALSE; } } void threadFn(int interval) { while (!stopFlag) { // 原有数据采集逻辑 // collect data and store in a vector // 替换原有sleep_for,超时等待条件变量 std::unique_lock<std::mutex> lock(g_mtx); auto cvRet = g_cv.wait_for(lock, std::chrono::seconds(interval)); if (cvRet == std::cv_status::no_timeout) { // 被主动唤醒,检查到停止标记则退出 if (stopFlag) break; } // 超时则继续下一轮循环 } // 原有数据统计输出逻辑 // accumulate vector values and display in the console } int main(int argc, char* argv[]) { SetConsoleCtrlHandler(CtrlHandler, TRUE); int interval = 10; // 示例间隔,可从用户输入获取 auto th = std::thread(threadFn, interval); if (th.joinable()) { th.join(); } return 0; }
额外注意点
- 原有代码中的
stopFlag需要声明为std::atomic<bool>类型,避免多线程访问的可见性问题,防止工作线程无法及时读取到停止标记的更新。 - 两种方案都可以做到在收到停止信号后10ms以内唤醒工作线程,完全满足你1~2秒内关闭的需求。
内容的提问来源于stack exchange,提问作者Arun
相关产品推荐
相关产品推荐

