执行器
头文件:<dlt698/common/executor.hpp>,命名空间 dlt698。
IExecutor
实现约定
如果你要自己实现 IExecutor,必须满足:
四条硬性约定
post/schedule必须延后执行任务。 不能在投递函数内直接调用用户任务。- 任务必须串行。 同一执行器上的任务不得并发。
- 异常必须隔离。 用户任务抛出的异常不能让执行器失效。
is_current()要覆盖整个执行环境。 在本执行环境的任务中返回true;共享 I/O 循环的实现须覆盖循环内所有 strand 的回调。 :::
第 4 条是死锁防护的基础。同步适配器用它拒绝会阻塞自己的调用——is_current() 为 true 时说明当前线程已经在执行器里,再同步等待就是自锁。
now() 使用单调时钟(steady_clock),不受系统日期调整影响。
ITimer::cancel() 幂等。释放计时器句柄本身不会取消回调——必须显式 cancel()。
库提供的实现
共享 strand 的执行器
IoRuntime::executor() 返回运行在独立 strand 上的会话执行器:
- 由同一个 runtime 驱动;
- 可以从不同线程投递任务;
- 多个泵送线程时,每个通道/监听器及会话执行器分别串行处理自身状态,不同实例的回调可以并发。
ManualExecutor
虚拟时钟从零开始。run_ready() 执行当前可运行的任务,包括任务中新投递的任务,并隔离回调异常。advance(elapsed) 推进虚拟时间并执行到期任务;elapsed 为负或超出可表示范围时抛 std::invalid_argument。
~ManualExecutor() 丢弃尚未驱动的任务和计时器。
:::warning 只限单线程
ManualExecutor 仅限单线程使用。它不创建线程、不跟随真实时间,是确定性模拟的基础。不要在多个线程上共享它。