[TOC]
一、核心设计原理 1. 执行器适配模式
1
2
3
|
class AimRTScheduler {
executor::ExecutorRef executor_ref_; // 核心适配对象
};
|
通过将框架的 Executor 对象适配为符合协程库要求的 Scheduler 对象,实现:
- 线程池调度( Execute() )
- 定时调度( ExecuteAt() / ExecuteAfter() )
- 跨执行器调度(通过 GetScheduler() 切换) 2. 双后端支持
1
2
3
4
5
|
#ifdef AIMRT_EXECUTOR_USE_STDEXEC
// 使用 stdexec 实现
#else
// 使用 unifex 实现
#endif
|
通过编译开关实现两种协程后端的无缝切换,差异主要体现在:
- 接口规范(STDEXEC 使用 C++23 标准,UNIFEX 使用自有规范)
- 类型特征( completion_signatures vs value_types/error_types )
- 操作符重载方式( tag_invoke vs 成员函数)
二、关键实现细节 1. 操作状态机(OperationState)
OperationState
1
2
3
4
5
6
7
8
|
template <typename Receiver>
struct OperationState {
void start() {
executor_ref_.Execute([receiver]{
set_value(receiver); // 实际调度点
});
}
};
|
实现原理:
- 接收协程返回的 receiver 对象
- 将协程 continuation 封装为 lambda
- 通过 Executor 提交到目标线程池 2. 定时调度实现
SchedulerAtOperationState
1
2
3
4
5
|
void start() {
executor_ref_.ExecuteAt(tp_, [receiver]{
set_value(receiver); // 定时触发
});
}
|
定时精度控制:
- 使用 std::chrono::system_clock 保证跨平台一致性
- 依赖 Executor 的定时队列实现(精度通常为毫秒级) 3. 上下文桥接
AimRTContext
1
2
3
|
AimRTScheduler GetScheduler(std::string_view name) {
return AimRTScheduler(executor_manager_.GetExecutor(name));
}
|
实现功能:
- 统一管理多个执行器的调度器实例
- 支持按名称获取不同特性的执行器(如 IO 密集型 vs CPU 密集型)
三、性能优化设计
1. 零内存分配
1
2
3
|
// 所有 OperationState 均通过模板参数静态确定
template <typename Receiver>
struct OperationState { /* 无动态内存分配 */ };
|
通过模板特化避免运行时类型擦除,保证:
2. 异常安全
1
2
3
4
5
|
try {
set_value(receiver);
} catch (...) {
set_error(receiver, std::current_exception());
}
|
统一异常处理策略:
- 捕获所有异常并传递到协程 continuation
- 避免跨线程异常丢失
四、典型调用流程
1
2
3
4
5
6
7
8
9
10
11
12
|
sequenceDiagram
participant Coroutine
participant Scheduler
participant Executor
participant ThreadPool
participant OperationState
Coroutine->>+Scheduler: co_await schedule()
Scheduler->>Executor: Execute(task)
Executor->>ThreadPool: 提交到工作队列
ThreadPool->>+OperationState: 执行 start() <!-- 激活 OperationState -->
OperationState->>-Coroutine: 恢复执行 <!-- 现在可以关闭 -->
|