尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

C++ 第 38 课:线程、SingleThreadedExecutor、MultiThreadedExecutor、Callback Group

C++ 第 38 课:线程、SingleThreadedExecutor、MultiThreadedExecutor、Callback Group 上一课答案1. 真正负责调度 callback 的是谁是Executorspin()更像是让 Executor 持续开始工作。2.rclcpp::spin(node)和 Executor 的关系可以粗略理解rclcpp::spin(node) ↓ ROS2帮你建立/使用Executor ↓ 把node交给它 ↓ Executor持续等待事件 ↓ 执行ready的callback3. Publisher 是不是主要靠 Executor 调度发送不是。例如publisher_-publish(msg);这句被执行时就主动调用 Publisher 发布消息。Publisher 本身不像 Subscriber / Timer 那样主要依赖一个“callback ready 后等待 Executor 执行”的模式。但publish()经常是在某个 callback 内部被调用。4. 单线程 Executor 中VLA callback 耗时 2 秒怎么办假设VLA callback 耗时2秒同时 Timer每10ms ready一次如果是单线程 ExecutorVLA callback执行 ↓ 唯一线程被占用2秒 ↓ Timer callback无法及时执行 ↓ 只能等待所以控制周期会严重延迟。5. Executor 能不能管理多个 Node可以。例如Executor ├── CameraNode ├── VLANode └── RobotControllerNodeExecutor 可以统一调度多个节点中的 callback。第 38 课线程、SingleThreadedExecutor、MultiThreadedExecutor、Callback Group这一课同时补C 并发基础 ROS2 并发模型。1. 先学一个新的 C 概念线程 Thread这是【C 新知识】。你以前可以把程序想成第1句 ↓ 第2句 ↓ 第3句这相当于一条执行路线。这条执行路线就可以粗略理解成一个Thread 线程例如void taskA() { // 做A } void taskB() { // 做B }如果只有一个线程taskA ↓ 执行完 ↓ taskB不能真正同时执行。2. 多线程是什么假设两个线程线程1 → taskA 线程2 → taskB那么在多核 CPU 上它们可能真正并行运行。例如线程1 VLA推理 线程2 机械臂控制这正是机器人系统为什么需要并发。3. SingleThreadedExecutorROS2SingleThreadedExecutor意味着Executor 使用一个主要执行线程处理 callback。假设Callback AVLA推理2000ms Callback B控制循环10ms执行A开始 ████████████████ 2秒 A结束 B才能开始于是 B 被卡住。4. MultiThreadedExecutor如果MultiThreadedExecutor有多个工作线程。可能变成线程1 ████████ VLA callback ████████ 线程2 control control control control ...这样VLA 推理不会必然完全阻塞控制 callback。5. 但“多线程”立刻带来一个新问题假设两个 callback 都访问double target_angle;Callback Atarget_angle 30.0;Callback Bdouble command target_angle;如果同时发生线程1正在写 target_angle 线程2正在读 target_angle就可能发生数据竞争 Data Race这是 C 并发里极其重要的概念。6. 什么叫数据竞争假设int x 0;线程 Ax 100;线程 Bstd::cout x;如果两个线程没有任何同步机制同时操作同一个变量 至少一个线程写就可能出现数据竞争。结果可能不可预测。7. ROS2 里这为什么非常现实未来你可能有actionCallback ↓ 修改 target_joint_ controlCallback ↓ 读取 target_joint_如果 MultiThreadedExecutor 同时执行线程1 actionCallback() 修改目标 线程2 controlCallback() 读取目标那么共享数据target_joint_就必须认真处理线程安全。8. 所以不能简单认为“多线程更快更好”单线程优点 简单 没有大量并发问题 缺点 一个callback太慢会阻塞其他callback多线程优点 不同callback可能并发 缺点 共享数据 竞态 锁 线程安全 调试难度所以工程设计不是“全部改 MultiThreadedExecutor 就完事。”9. ROS2 引入 Callback Group这是【ROS2 新知识】。Callback Group 可以理解成给 callback 分组并告诉 Executor 哪些 callback 能不能同时执行。最重要的两类MutuallyExclusive Reentrant10. MutuallyExclusive意思同一个 group 里的 callback 不允许同时执行。比如Callback Group A ├── jointStateCallback └── controlCallback设置为MutuallyExclusive那么即使使用多线程 ExecutorjointStateCallback 和 controlCallback也不会同时执行。11. 为什么有用因为它们可能共同访问joint_state_你不希望一个正在修改一个正在读取。所以互斥执行可以降低并发风险。12. Reentrant意思这个 group 里的 callback 可以并发执行甚至同一种 callback 也可能同时被调用。适合本身就是线程安全、互不影响的任务。这个比MutuallyExclusive更需要你理解线程安全。13. 所以 Executor 和 Callback Group 是不同层级可以画MultiThreadedExecutor │ ▼ Node │ ┌────┴────┐ │ │ Group A Group B │ │ callback callbackExecutor负责调度。Callback Group限制哪些 callback 可以并发。14. VLA 场景怎么设计例如RobotController Node │ ├── Group AMutuallyExclusive │ ├── jointStateCallback │ └── controlTimerCallback │ └── Group B └── vlaCallback概念目标控制和状态更新 → 尽量保证一致性 VLA推理 → 不要长时间堵住控制循环但真实系统里VLA 大模型通常还会进一步独立进程 / 独立 Node / Python 节点 / 推理服务器而不是简单塞进一个 callback 里跑几秒。15. 为什么更推荐把 VLA 和控制拆成不同 Node例如VLANode Python PyTorch 负责 视觉 语言 模型推理 动作生成和RobotController C ROS2 负责 高频状态 安全检查 轨迹下发 控制中间Topic / Action通信。这就是 VLA 系统非常合理的一种架构Python VLA ↓ 低频高级动作 ↓ ROS2通信 ↓ C控制节点 ↓ 高频可靠控制而不是C控制callback里面 直接跑20亿参数模型16. C真正的多线程以后怎么写你以后会学#include thread std::thread t(task);以及std::mutex std::lock_guard std::condition_variable std::atomic这些不会只作为 ROS2 附属概念。我们会专门系统学习线程 共享内存 锁 死锁 数据竞争 原子变量 条件变量 线程生命周期因为这本身就是现代 C 的重要部分。17. 当前理解层级现在先形成程序 ↓ 可以有多个线程 Executor ↓ 用线程执行ROS2 callback SingleThreadedExecutor ↓ 基本一个执行线程 MultiThreadedExecutor ↓ 允许多个callback并发 Callback Group ↓ 进一步约束哪些callback允许并发 共享数据 ↓ 必须考虑线程安全这条链非常重要。18. VLA 实际案例假设VLA输出周期 500ms 机械臂控制周期 10ms如果两者强行单线程VLA执行500ms ↓ 控制循环被卡500ms对机械臂几乎不可接受。合理架构更接近VLA Node 500ms一次高级动作 │ ▼ ROS2 Topic │ ▼ RobotController 10ms控制循环两边不同运行节奏。所以ROS2 不只是通信工具它还帮助你把不同时间尺度的机器人功能拆开。本课小练习SingleThreadedExecutor 为什么容易被长时间 callback 阻塞MultiThreadedExecutor 最大的优势和最大的风险分别是什么两个线程同时操作同一个变量并且至少一个线程写可能产生什么问题MutuallyExclusiveCallback Group 主要限制什么如果 VLA 推理 500ms而机械臂控制需要 10ms 一次你更倾向把它们放在同一个阻塞 callback还是拆开为什么
返回列表