You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何中断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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 05:39:03