该文提出五种c++延迟任务调度方案:一、多级独立队列轮询,避免锁竞争;二、时间轮与优先级队列混合调度,解耦短/长延迟任务;三、c++26标准库协程调度;四、std::jthread+stop_token带状态记忆轮询;五、支持取消与退避重试的retrytask封装。

一、基于多级独立队列的轮询调度实现
该方法通过为不同优先级任务分配独立队列,避免单 priority_queue 在并发环境下的锁竞争与调度僵化问题。每个队列使用独立互斥锁,轮询器按固定顺序扫描非空队列并取一个任务执行,从而保障高优先级任务不被低优先级任务阻塞,同时防止某一级别长期独占线程。
1、定义优先级枚举:使用 enum class Priority { HIGHEST = 0, HIGH = 1, MEDIUM = 2, LOW = 3, LOWEST = 4 };
2、声明多级队列容器:std::array<:queue>, 5> queues;
3、为每级队列声明独立 std::mutex:std::array<:mutex> mutexes;
4、在调度主循环中维护当前轮询索引 current_level,并在每次迭代开始前检查 token.stop_requested();
5、对 current_level 对应队列调用 try_lock(),成功则 pop 任务并立即检查 cancelled.load(),失败则跳至下一级;
6、若某级队列为空或锁获取失败,递增 current_level 并对 5 取模,继续轮询;
7、任务取出后,根据 scheduled_at 字段判断是否已到期:若未到期,则重新入队至对应优先级队列(不改变原始 priority),并继续下一轮轮询。
二、融合时间轮(Timing Wheel)与优先级队列的混合调度
该方法将延迟任务与即时任务解耦处理:短期延迟(≤ 64ms)由时间轮高效触发,长期延迟及高优先级即时任务交由多级优先队列分发。时间轮采用无锁数组结构,避免频繁内存分配,且与优先级队列共享同一 stop_token 退出机制,确保调度器整体一致性。
1、初始化 8 层时间轮(每层 256 槽),支持最大延迟约 16 秒;
2、任务入队时,若 delay ≤ 64ms,插入对应时间轮槽位;否则根据 priority 字段落入对应多级队列;
3、调度线程每 1ms 调用一次 tick(),遍历当前槽位所有任务,将其 move 到对应优先级队列头部;
4、在轮询多级队列前,先执行一次 tick(),确保刚到期任务已就绪;
5、为防止时间轮槽位堆积,每个槽位使用 std::vector
6、所有 Task 对象存储于 std::pmr::unsynchronized_pool_resource 分配器中,规避 new/delete 频繁调用开销;
7、时间轮指针推进与队列轮询必须在同一原子周期内完成,使用 std::atomic_thread_fence(std::memory_order_acquire) 保证可见性。
三、C++26 std::priority_task_queue + std::execution::async_policy 协同调度
该方法直接利用 C++26 标准库新特性构建轻量级异步延迟调度引擎,无需手动管理线程与锁。std::priority_task_queue 提供线程安全的优先级入队/出队,配合 std::execution::async_policy 实现任务提交即调度,延迟由任务体内部 co_await std::when_timeout() 控制,适用于对标准合规性要求严格的工业场景。
1、包含头文件:#include
2、定义任务结构体,含 priority 字段与 action 成员函数对象;
3、构造 std::priority_task_queue
4、封装 submit_delayed() 函数:接收 delay 参数,内部创建协程,首句为 co_await std::when_timeout(delay);
5、协程挂起后,将封装后的可调用对象以 async_policy 提交至 queue;
6、启动专用调度线程,循环调用 queue.process_one(),该函数自动处理协程恢复与异常捕获;
7、当 stop_token 触发时,process_one() 返回 false,线程安全退出,无需手动 join 或 detach。
四、基于 std::jthread + stop_token 的带状态记忆轮询器
该方法聚焦于调度器生命周期控制的健壮性,使用 std::jthread 替代裸 std::thread,结合 stop_token 实现零竞态退出。轮询逻辑携带状态记忆(如 last_served_level、consecutive_high_count),用于动态调节轮询权重,缓解高优先级任务持续涌入导致的低优先级任务饥饿问题。
1、在 ThreadPool 构造函数中初始化 std::jthread scheduler_thread,绑定成员函数 run_scheduler;
2、run_scheduler 函数开头即检查 token.stop_requested(),若为 true 则立即 return;
3、维护 std::atomic
4、每次成功执行一个任务后,对应 level_counters[current_level].fetch_add(1);
5、若 level_counters[current_level] > 3,则强制跳过下两个同级轮询机会,转而尝试 next_level;
6、每次 pop 任务前,再次调用 token.stop_requested(),若已请求停止,则放弃本次 pop 并 break 循环;
7、任务执行体 lambda 显式接收 std::stop_token,并在 sleep 或 I/O 等待前插入 token.stop_requested() 检查。
五、支持取消与退避重试的延迟优先级任务封装
该方法面向真实业务场景,将延迟、优先级、取消、重试四大能力统一建模为 RetryTask 类型。每个任务携带 base_delay、max_retry、backoff_factor 与 priority 字段,调度引擎仅需识别其为可重试类型,即可自动注入退避逻辑与超时熔断,无需上层重复编码。
1、定义 RetryTask 继承自 Task,新增 retry_count、next_delay_ms、max_retry 字段;
2、任务首次入队时,scheduled_at 设置为 steady_clock::now() + base_delay;
3、执行失败时,若 retry_count
4、重试任务入队前,优先级自动提升一级(但不超过 HIGHEST),防止重试被长期压在低优队列底部;
5、所有 RetryTask 共享一个 std::unordered_set<:uintptr_t> active_ids,用于 cancel_by_id() 快速查找;
6、cancel_by_id() 调用时,不仅设置 cancelled = true,还从对应队列中移除该任务(需持有对应 mutex);
7、调度器在 process_one() 中对每个任务执行前,检查 active_ids 是否仍包含其地址,若否,则跳过执行并清理元数据。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











