百度Apollo系统学习-Cyber RT 调度

本文深入探讨了百度Apollo系统中的CyberRT框架调度机制,包括Component与TimerComponent的工作原理,CyberRT中协程(Croutine)与任务(Task)的概念,以及SchedulerClassic与SchedulerChoreography两种调度策略的运作细节。

简介

在上一篇文章中我们介绍了cyber里如何注册加载模块,同时也找到了cyber的程序入口。现在我们就会想问,这些功能组件加载进来以后它们又该怎么运行呢,cyber是怎么安排它们有序工作的呢?这篇文章就带大家来解答这些问题。

Component回顾与深入探究

我们虽然在注册启动模块的文章中大概了解到Component是构成module的组件,但并不清楚其内部的具体结构,现在我们就仔细看一看Component到底是什么。以下部分内容的具体解析见参考链接。

继承关系

Component的基类是ComponentBase(位于cyber/component/component_base.h),它有两个子类Component和TimerComponent,用户定义的组件都是继承这两个子类,然后需要实现其中的Init() & Proc()函数。

ComponentBase

ComponentBase是组件的基类,组件类的所有成员变量都在此进行了定义,所以我们看一下每个成员。

  • std::atomic is_shutdown_ = {false};记录了该组件是否已经停止
  • std::shared_ptr node_ = nullptr;Node节点,下面会具体解释
  • std::string config_file_path_ = “”;记录组件的配置文件,在不同module对应的dag文件中每个components or timer_components字段里(注意,并不是modules/xxx/conf文件夹里的.conf.pb.txt),初始化组件时传入的参数就是这个。
  • std::vector<std::shared_ptr> readers_;记录该组件用来读取信息的阅读器(代码在cyber/node/reader_base

Node

每个Component都有一个Node,每个Node负责创建Reader, Writer, Service, Client来帮该组件获取信息或传达信息。每个Node保存了它的名字和名字空间,一个存有channel对应的Reader的map以及一个NodeChannelImpl和一个NodeServiceImpl(创建以上4种东西的创建器)。有关Reader等具体通信相关的类会在之后的博客中在详细介绍,现在只需要知道Node创建的这几个实例都是用来通信的。

Component & TimerComponent

TimerComponent是通过定时调用它的Proc来运行的,TimerComponent运行时会创建task_pool_sizescheduler成员,可在配置文件中配置,具体见下文)数量的协程,协程名字为/internal/task+[number](代码位于cyber/task/task_manager.cc),相关任务是通过TaskManager::Enqueue加入的,这里面涉及的内容太多且和本次主题不相关,后面如果有必要我会再出一篇详解一下Timer机制。接下去我们关注以Component为主。

Component

Tip:以下内容在阅读代码时会碰到Lambda函数的使用,建议读者可以先学习一下c++中Lambda函数再阅读源码。

  • ComponentInitialize() & Process()都最终会调用到子类实现的Init() & Proc()函数。
  • Initialize函数
    1. 每个Component可以读取0-4个不同的消息种类(每种对应一个不同的Component,但如果是0那就是完全不读取消息,对于这个情况cyber也没有调度,甚至连Process函数都没有,可见运行比较特殊,估计是运行一次就结束的那种),在初始化某种组件的时候,会先初始化Node然后读入配置文件,如果发现配置文件里设置的reader数量少于该种类Component定义的接受消息个数的话,就会报错。
    2. 接下去会查看当前运行是在现实环境还是虚拟环境并读取配置文件里定义的reader的各种设置(channel名字,qos策略,pending队列长度),然后根据这些配置创建相应的Reader并放入组件的阅读器队列中。
    3. 如果是现实环境,创建的ReaderWriter都是普通的,如果是虚拟环境最终创建的会是IntraReaderIntraWriter(在cyber/blocker/中),并且虚拟环境下,调度器也是不会使用的,所以接下去我们也主要看现实环境。
    4. 现实环境下,Initialize函数接下来就会获取调度器实例,创建回调函数,设置数据获取器(data::DataVisitor见通信章节博客),然后以该回调函数以及数据获取器为参数创建协程工厂,最后创建Task

几个基本概念

Croutine & Task

Croutine(协程)就是可以人为暂停执行的函数,cyber中的croutine位于

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值