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
相关产品推荐
相关产品推荐

