CyberRT(apollo) 定时器模块简述及bug分析

timer 模块

timer的定义,cyberrt中timer模块用于设置定时器任务,字面意思,设置设置定时周期及出发频次(周期 or oneshot),到达指定时间时间触发callback

time wheel

时钟节拍轮,常见的定时器设计,例如ucos中的定时器,Linux Crontab等,cyberrt也是采用了时钟轮

时间轮(TimingWheel)简单来说,是一个 存储定时任务的循环队列,队列中的每个元素都可以放置一个定时任务列表(TimeBucket) 。TimeBucket 是一个list,链表中的每一项表示的都是定时任务(TimerTask)。

时钟轮示意图

alt text

类图

在这里插入图片描述

@startuml
class Timer{
+explicit Timer(TimerOption opt)
+void Start()
+void Stop()
-TimerOption timer_opt_;
-TimingWheel* timing_wheel_ = nullptr;
-std::shared_ptr<TimerTask> task_;
}
class TimingWheel {- TimerBucket work_wheel_[WORK_WHEEL_SIZE]- TimerBucket assistant_wheel_[ASSISTANT_WHEEL_SIZE]- std::thread tick_thread_+ ~TimingWheel()+ void Start()+ void Shutdown()+ void Tick()+ void AddTask(const std::shared_ptr<TimerTask>& task)  + void TickFunc()}
class TimerBucket {- std::mutex mutex_- std::list<std::weak_ptr<TimerTask>> task_list_+ void AddTask(const std::shared_ptr<TimerTask>& task)+ std::mutex& mutex()+ std::list<std::weak_ptr<TimerTask>>& task_list()
}struct TimerTask {+ TimerTask(uint64_t timer_id)+ uint64_t timer_id_+ std::function<void()> callback+ uint64_t interval_ms+ uint64_t remainder_interval_ms+ uint64_t next_fire_duration_ms+ int64_t accumulated_error_ns+ uint64_t last_execute_time_ns+ std::mutex mutex
}
class TimerOption {+ uint32_t period+ std::function<void()> callback+ bool oneshot+ TimerOption(uint32_t period, std::function<void()> callback, bool oneshot)+ TimerOption()
}note left of Timer外部主要调用类,定时器对象实体
end notenote left of TimerOption配置参数,主要作为入参构造timer,用于配置定时器
end notenote left of TimingWheel环形队列,cyberrt内部实现为二级时钟节拍轮,单例
end notenote left of TimerBucket环形队列中的元素,为链表,存储std::weak_ptr<TimerTask>,等价线程安全的list<std::weak_ptr<TimerTask>>
end noteTimer --> TimerOption : 入参依赖 
Timer --> TimingWheel : 成员依赖 
TimingWheel --> TimerBucket : 成员依赖 
TimerBucket --> TimerTask : 成员依赖 @enduml

实现原理

timingwheel 中的tick线程用于统计时间时间,并获取指向的时钟节拍论里面的元素进行任务触发,并将任务丢到cyberrt的携程池里运行,timewheel的实现基本都大同小异,这里不细说。

bug

bug主要是call back的生命周期管理问题,在代码中其实已经考虑了一部分(shared_ptr+weak_ptr)已经保证了一部分的悬空指针的问题,但是不完全。

 bool Timer::InitTimerTask() {task_.reset(new TimerTask(timer_id_));task_->interval_ms = timer_opt_.period;task_->next_fire_duration_ms = task_->interval_ms;if (timer_opt_.oneshot) {std::weak_ptr<TimerTask> task_weak_ptr = task_;task_->callback = [callback = this->timer_opt_.callback, task_weak_ptr]() {auto task = task_weak_ptr.lock();if (task) {std::lock_guard<std::mutex> lg(task->mutex);callback();}};} else {std::weak_ptr<TimerTask> task_weak_ptr = task_;task_->callback = [callback = this->timer_opt_.callback, task_weak_ptr]() {auto task = task_weak_ptr.lock();if (!task) {return;}XXXX //省略TimingWheel::Instance()->AddTask(task);};}return true;
}void TimingWheel::Tick() {auto& bucket = work_wheel_[current_work_wheel_index_];{std::lock_guard<std::mutex> lock(bucket.mutex());auto ite = bucket.task_list().begin();while (ite != bucket.task_list().end()) {auto task = ite->lock();if (task) {ADEBUG << "index: " << current_work_wheel_index_<< " timer id: " << task->timer_id_;auto* callback =reinterpret_cast<std::function<void()>*>(&(task->callback));cyber::Async([this, callback] {if (this->running_) {(*callback)();}});}ite = bucket.task_list().erase(ite);}}
}

以上代码,构建TimerTask添加到timing wheel中,task为share_ptr,所有权归属timer对象很合理,传递weak_ptr对象給timingWhee,timer对象释放后,节拍轮里面的weak_ptr不再有效进行不必要的触发,这也很正确,合理的考虑了timer对象持有的task和timingwheel中task的异步生命周期管理的问题。

但是在tick函数中,将触发的task放到异步协程池运行的时候则出现问题了,未考虑异步生命周期的问题。

现在假设我们有这样一个场景

创建了一个10ms的周期timer,经过第一个10ms时触发了定时器并将回掉丢到协程池中并推出tick,假设当时协程池比较繁忙,有恰巧我们迅速释放掉timer对象或者stop掉timer对象,you lose,程序boom了。

因为传递task这个share_ptr对象里的callback 成员函数进行了异步调用,tick函数内虽然正确获取了task,退出该函数,task引用计数-1,于此同时我们stop了timer 对象s或者 析构了对象,time持有的task,引用再次-1归0,tick函数内cyber::Async虽然正确获取了task的callback,但此时,已经是悬空指针了。

修改

知道了原因,改起来也很方便,无非就是异步调用指针的管理而已。

void TimingWheel::Tick() {auto& bucket = work_wheel_[current_work_wheel_index_];{std::lock_guard<std::mutex> lock(bucket.mutex());auto ite = bucket.task_list().begin();while (ite != bucket.task_list().end()) {auto task = ite->lock();if (task) {ADEBUG << "index: " << current_work_wheel_index_<< " timer id: " << task->timer_id_;// auto* callback =//   reinterpret_cast<std::function<void()>*>(&(task->callback));cyber::Async([this, weakTask = std::weak_ptr<TimerTask>(task)] {auto task = weakTask->lock();if (this->running_ && task ) {task->callback();}});}ite = bucket.task_list().erase(ite);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/27794.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用ast获取py文件中所有函数与类名

当我们在创建python项目,经常需要遍历和分析代码文件&#xff0c;特别是当我们想要自动化地获取某些信息&#xff0c;比如所有的函数和类名。Python的ast&#xff08;Abstract Syntax Trees&#xff0c;抽象语法树&#xff09;模块为我们提供了一个强大的工具&#xff0c;可以方…

【C语言5】函数:库函数、自定义函数、形参和实参、return语句、数组做函数参数、嵌套调用和链式访问、声明和定义

文章目录 一、函数的概念二、库函数2.1 标准库和头文件2.2 库函数的使用方法 三、自定义函数3.1 函数的语法形式 四、形参和实参4.1 实参4.2 形参4.2 实参和形参的关系 五、return 语句六、数组做函数参数七、嵌套调用和链式访问7.1 嵌套调用7.2 链式访问 八、函数的声明和定义…

【项目管理】基于 C 语言的 QQ 聊天室实现(TCP + 多线程 + SQLite3)

基于 C 语言的 QQ 聊天室(TCP + 多线程 + SQLite3) 项目功能基础功能: 登录、注册、添加好友、私聊、创建群聊、群聊扩展功能: 删除好友、注销账号、好友在线状态、群管理(拉人/踢人)、VIP 特权、邮件通知等 功能介绍:模拟QQ聊天客户端:登录界面:1、登录2、注册 //将用…

vscode 都有哪些大模型编程插件

VSCode 中有许多基于大模型的编程插件&#xff0c;这些插件通过集成人工智能技术&#xff0c;显著提升了开发者的编程效率和体验。以下是一些主要的大模型编程插件及其功能&#xff1a; GitHub Copilot GitHub Copilot 是由 OpenAI 开发的插件&#xff0c;能够根据代码上下文自…

每日一题洛谷普及/提高-P1154 奶牛分厩c++

无注释版 #include<iostream> #include<cstring> #include<cstdlib> using namespace std; bool ju(int n, int s[], int len, bool a[]) {memset(a, 0, n * sizeof(bool));for (int j 0; j < len; j) {if (a[s[j] % n]) {return false;}a[s[j] % n] t…

[liorf_localization_imuPreintegration-2] process has died

使用liorf&#xff0c;编译没报错&#xff0c;但是roslaunch报错如下&#xff1a; 解决方法&#xff1a; step1: 如果你之前没有安装 GTSAM&#xff0c;可以尝试安装它 step2: 检查是否缺少依赖库 ldd /home/zz/1210/devel/lib/liorf_localization/liorf_localization_imuPr…

Jmeter+ant+jenkins接口自动化测试

平台简介 一个完整的接口自动化测试平台需要支持接口的自动执行&#xff0c;自动生成测试报告&#xff0c;以及持续集成。Jmeter 支持接口的测试&#xff0c;Ant 支持自动构建&#xff0c;而 Jenkins 支持持续集成&#xff0c;所以三者组合在一起可以构成一个功能完善的接口自动…

springboot425-基于SpringBoot的BUG管理系统(源码+数据库+纯前后端分离+部署讲解等)

&#x1f495;&#x1f495;作者&#xff1a; 爱笑学姐 &#x1f495;&#x1f495;个人简介&#xff1a;十年Java&#xff0c;Python美女程序员一枚&#xff0c;精通计算机专业前后端各类框架。 &#x1f495;&#x1f495;各类成品Java毕设 。javaweb&#xff0c;ssm&#xf…

如何将飞书多维表格与DeepSeek R1结合使用:效率提升的完美搭档

将飞书的多维表格与DeepSeek R1结合使用&#xff0c;就像为你的数据管理和分析之旅装上一台涡轮增压器。两者的合作&#xff0c;不仅仅在速度上让人耳目一新&#xff0c;更是将智能化分析带入了日常的工作场景。以下是它们如何相辅相成并改变我们工作方式的一些分享。 --- 在…

leetcode 148. 排序链表

题目如下 数据范围 通过代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : va…

关于对机器中的人工智能进行基准测试

大家读完觉得有帮助记得及时关注和点赞&#xff01;&#xff01;&#xff01; 抽象 最近的基准研究声称&#xff0c;AI 在各种认知任务上的表现已经接近甚至超过人类的“水平”。然而&#xff0c;本立场文件认为&#xff0c;当前的 AI 评估范式不足以评估类似人类的认知能力。我…

C# OnnxRuntime部署DAMO-YOLO交通标识检测

目录 说明 效果 模型信息 项目 代码 下载 参考 说明 效果 模型信息 Model Properties ------------------------- --------------------------------------------------------------- Inputs ------------------------- name&#xff1a;input tensor&#xff1a;Floa…

【开源-鸿蒙土拨鼠大理石系统】鸿蒙 HarmonyOS Next App+微信小程序+云平台

✨本人自己开发的开源项目&#xff1a;土拨鼠充电系统 ✨踩坑不易&#xff0c;还希望各位大佬支持一下&#xff0c;在GitHub给我点个 Start ⭐⭐&#x1f44d;&#x1f44d; ✍GitHub开源项目地址&#x1f449;&#xff1a;https://github.com/cheinlu/HarmonyOS-groundhog-mar…

QT实现单个控制点在曲线上的贝塞尔曲线

最终效果: 一共三个文件 main.cpp #include <QApplication> #include "SplineBoard.h" int main(int argc,char** argv) {QApplication a(argc, argv);SplineBoard b;b.setWindowTitle("标准的贝塞尔曲线");b.show();SplineBoard b2(0.0001);b2.sh…

深入探索Python机器学习算法:监督学习(线性回归,逻辑回归,决策树与随机森林,支持向量机,K近邻算法)

文章目录 深入探索Python机器学习算法&#xff1a;监督学习一、线性回归二、逻辑回归三、决策树与随机森林四、支持向量机五、K近邻算法 深入探索Python机器学习算法&#xff1a;监督学习 在机器学习领域&#xff0c;Python凭借其丰富的库和简洁的语法成为了众多数据科学家和机…

二、QT和驱动模块实现智能家居-----问题汇总1

1、文件地址改变后必须在QT下更改地址 2、指定了QT内Kits下的Sysroot头文件地址&#xff0c;但是还是找不到头文件&#xff1a; 3、提示无法执行QT程序&#xff1a;先干掉之前的QT程序 ps //查看程序PIDkill -9 PID 4、无法执行QT程序 1&#xff09;未设置环境变量 …

【Linux专栏_1】Linux中常用的指令

文章目录 前言1、查看Linux主机ip2、 Linux下的常用指令集合(1)、ls指令(2)、pwd指令(3)、cd指令(4)、touch指令(5)、mkdir指令(6)、rmdir和rm删除指令(7)、man指令(8)、cp指令(9)、mv指令(10)、cat指令(11)、more指令(12)、date指令(13)、cal指令(14)、find指令(15)、which指令…

Android+SpringBoot的老年人健康饮食小程序平台

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 系统介绍 我将从经济、生活节奏、技术融合等方面入手&#xff0c;详细阐述居家养老管理模式兴起的…

yoloV5的学习-pycharm版本

真的很让人气愤的一点&#xff0c;老师把我的pycharm给卸载了&#xff0c;我那个上面不仅有gpu-torch&#xff0c;还有gpu-torch&#xff0c;他给俺删了&#xff0c;删了很久&#xff0c;我心都碎了&#xff0c;过几天我就去找他负责&#xff0c;让他给我装回来我的环境&#x…

DeepSeek搭配Excel,制作自定义按钮,实现办公自动化!

今天跟大家分享下我们如何将DeepSeek生成的VBA代码&#xff0c;做成按钮&#xff0c;将其永久保存在我们的Excel表格中&#xff0c;下次遇到类似的问题&#xff0c;直接在Excel中点击按钮&#xff0c;就能10秒搞定&#xff0c;操作也非常的简单. 一、代码准备 代码可以直接询问…