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

C++20实现无sleep_for无限循环的后台定时任务

如何在C++20中实现无显式sleep和无限循环的后台定时任务?

我想创建一个后台无限定时器,定期输出队列大小。目前用std::async实现,但想去掉std::this_thread::sleep_for和无限循环的写法,有没有办法直接把超时间隔传入std::async或其他C++20工具?希望工作函数只负责输出队列大小,不带额外逻辑。现有代码如下:

#include <iostream>
#include <future>
#include <thread>
#include <chrono>

// 假设queueSize是全局变量或可访问的变量
size_t queueSize = 0;

void backgroundTimer(int secondsTimeout)
{
    while (true)
    {
        std::this_thread::sleep_for(std::chrono::seconds(secondsTimeout));
        std::cout << "Queue size: " << queueSize << std::endl;
    }
}

int main(int argc, const char* argv[])
{
    std::async(backgroundTimer, 1);

    // 其他业务逻辑...
    return 0;
}

方案1:用std::jthread结合stop_token和定时等待

C++20引入的std::jthread自带线程自动管理和中断机制,我们可以用std::condition_variable_any的wait_for替代显式sleep,同时通过stop_token优雅控制线程终止,彻底去掉硬编码的无限循环:

#include <iostream>
#include <thread>
#include <chrono>
#include <condition_variable>

size_t queueSize = 0;

void backgroundTimer(std::stop_token stoken, std::chrono::seconds interval)
{
    std::condition_variable_any cv;
    std::mutex mtx;

    // 注册停止回调,线程终止时唤醒等待的cv
    auto stop_callback = stoken.register_callback([&cv]() { cv.notify_one(); });

    while (!stoken.stop_requested())
    {
        // 等待指定间隔,或被中断唤醒
        cv.wait_for(mtx, stoken, interval, []{ return false; });
        if (!stoken.stop_requested())
        {
            std::cout << "Queue size: " << queueSize << std::endl;
        }
    }
}

int main()
{
    // 创建jthread,自动管理生命周期,传入间隔参数
    std::jthread timer_thread(backgroundTimer, std::chrono::seconds(1));

    // 其他业务逻辑...

    // 主线程结束时,jthread会自动请求停止并完成join
    return 0;
}

核心优势:

  • 没有硬编码的while(true),通过stop_token判断终止条件,逻辑更清晰
  • 用wait_for替代sleep_for,支持线程即时中断,避免sleep期间无法响应终止信号
  • 工作函数仅在定时触发时执行输出逻辑,完全符合职责单一的要求

方案2:封装周期性任务工具,让业务函数彻底解耦

如果想让业务函数完全脱离定时逻辑,可以把周期性触发的循环封装成通用工具,业务函数只负责输出队列大小:

#include <iostream>
#include <thread>
#include <chrono>
#include <functional>

// 通用周期性任务封装
template<typename Func, typename Rep, typename Period>
void periodic_task(std::stop_token stoken, const std::chrono::duration<Rep, Period>& interval, Func func)
{
    std::condition_variable_any cv;
    std::mutex mtx;

    auto stop_cb = stoken.register_callback([&cv]() { cv.notify_one(); });

    while (!stoken.stop_requested())
    {
        cv.wait_for(mtx, stoken, interval, []{ return false; });
        if (!stoken.stop_requested())
        {
            func();
        }
    }
}

size_t queueSize = 0;

// 纯业务函数,仅负责输出队列大小
void printQueueSize()
{
    std::cout << "Queue size: " << queueSize << std::endl;
}

int main()
{
    // 创建定时线程,传入间隔和业务函数
    std::jthread timer_thread(periodic_task<decltype(printQueueSize), int, std::ratio<1>>,
                              std::chrono::seconds(1), printQueueSize);

    // 其他业务逻辑...

    return 0;
}

核心优势:

  • 业务函数printQueueSize完全无额外逻辑,实现彻底解耦
  • 周期性触发逻辑封装在工具函数中,可复用在其他定时场景
  • 同样借助std::jthread的自动管理机制,无需手动处理线程终止

关于std::async的说明

std::async本质只是异步执行任务的工具,没有内置的定时触发能力。如果硬要用std::async实现定时任务,仍然需要结合循环和定时等待,无法避开你想去掉的结构。相比之下,std::jthread是C++20专为长期运行的后台线程设计的工具,支持中断和自动join,更适合这类场景。

内容的提问来源于stack exchange,提问作者Hardwired

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 12:52:31