软件实时性: “快是优点么?”
扫描二维码
随时随地手机看文章
关注+星标公众号,不错过精彩内容
作者 | 傻孩子
转自 | 裸机思维
下面分享一篇王工(网名:傻孩子)整理的文章:
【序】
不知道你发现没有,平时我们讨论嵌入式软件开发时总绕不开与实时性(Real Time)相关的话题。相信不少朋友和我一样是通过实时性操作系统(Real Time Operating System, RTOS)第一次接触到实时性概念的——我记得那还是大学时代、参加机器人竞赛的时候。工作以后自信地以为加深了不少对实时性的本质认识——现在看来其实还未摸到门道。就这样浑浑噩噩一直到毕业后的第八年,因为工作变动的原因,我被迫要在一周内要做一个实时性原理相关的研究报告,也就在那时,我体会到了疯狂练功走火入魔的感觉:走路在思考、吃饭在看资料、头一直发烧一样的微微发热、甚至连睡觉都在梦中推演模型——头发一把一把的掉,幸好有截稿时间,否则真的要秃了。
-
Lv1:“实时性” = “越快越好”,认为用好中断是保证实时性的关键;这类朋友通常最擅长的是裸机下的“前后台系统”; -
Lv2:“实时性” = RTOS,认为选一个好的RTOS,或者会用RTOS就可以保证实时性;这一阶段的朋友对RTOS充满了好奇,以编写自己的RTOS为“ 终(zhong)极(er)目标”; -
Lv3:“实时性” = 任务拆分,这一阶段已经能正确的理解实时性窗口的概念,意识到实时性并不意味着越快越好,但也认为“在可能的情况下”“快一点响应事件没啥坏处”;这一阶段的朋友可能已经可以在裸机和RTOS之间自由的反复横跳,无论是裸机下的状态机还是RTOS下的线程都已了如指掌、任务间通信更是游刃有余; -
Lv4:这一阶段开始思考实时性模型的特点,并逐渐意识到模型本身其实隐含了足以颠覆过往所有关于实时性认知的秘密;到达这一阶段的朋友通常觉得没必要、也没心思继续思考实时性更本质的数学意义——因为此时获得的结论已经足够了应付几乎所有的工程开发了。顺便说一下,我就在这里 。 -
Lv5:到了这个阶段,不仅脑洞大开、战斗力惊人、估计打针也没法阻止你抓破脖子了吧 ——以上只是暴露年龄的玩笑,但肯定 可以水几篇SCI论文了……
在理解了实时性的模型以后,我(本能的排除了自己比较笨这个可能性,然后)意识到:其实这一过程完全没必要如此漫长和曲折——很多结论和道理是如此简单——不仅书本上有,而且解释和学习起来都不费什么力气。可能这就是“挠破头”想通某个道理之后,回头再看时忍不住要“苦笑”时的感受吧。
按照约定,为了将经验和知识分享给大家,从本文开始,我将以几篇文章的篇幅:从基础模型开始,由浅入深、由理论到实践,推演关于实时性的几个重要结论——从而直接跳跃到Lv4的认知阶段。如果你看了这个系列后有什么话想说的、想问的,还请在评论区写下您的留言。求评论、求转发、求收藏。
-
基于物理世界客观法则的限制,很多应用在制定需求说明的时候,从某一个事件发生的时刻计算,会规定一个死线(Dead Line),即:一旦事件发生了,如果不在这个死线之前完成整个对事件的处理,就视作失败; -
这里,从事件发生到死线这段时间长度,习惯上称为实时性窗口。当事件发生时,只有在死线内任意时刻完成了对事件的处理,才能称为实时性得到了满足; -
容易注意到,处理事件的过程也需要消耗时间——一般称为事件处理时间;
图1 实时性基本模型
考虑一个有趣的问题:对一个实时性任务来说,实时性窗口内的时间,其价值是一样的么?换句话说,横竖处理事件消耗的时间是不变的,早点做迟点做都是做,有什么区别么?
图2 实时性窗口内不同时间段完成事件响应
对比图2所示的三种情况,可以很清楚的得出结论:理论上,从满足实时性的角度出发,在时间窗口内任意时段完成对事件的处理都满足实时性要求;早做没有任何额外的好处,“踩着上课铃到校”也没有任何惩罚——简单说就是早做迟做无所谓。
你说“我不管,我不管”,既然什么时候做都一样为什么不能“尽早做”?“你也说了尽早做没啥不好”,“中断来了,服务程序执行了,我想让它迟点执行也做不到啊?”
为了回答这个问题,我们不讲大道理,先看一个常见的例子:
-
超级循环里有三个任务A、B和C;
void main(void)
{
...
while(1) {
task_a();
task_b();
task_c();
}
}
-
每个任务都使用轮询的方式在等待一个来自芯片外界的事件发生(先不考虑存在中断的情况); -
当一个任务函数被执行时会检查对应的事件是否已经发生,如果确实已经发生,则执行后续的处理;反之则立即退出任务函数——释放处理器; -
A、B、C三个事件的实时性窗口分别为10ms, 6ms和4ms;处理三个事件的处理程序分别需要4ms、3ms和0.4ms。如图3所示:
图3 三个事件的实时性窗口和事件处理时间示意图
-
需要强调的是,task_a()、task_b()和task_c()三个函数的策略本质上都是一样的——“一旦检测到事件立即处理,绝不迟延”!
图 4 “越快处理越好” 导致其它任务无法满足实时性要求
通过上面的例子,我们知道“越快处理越好”是值得反思的——至少会存在情况导致系统在某些时刻无法满足实时性要求;那么从模型上来说,如何理解这一现象呢?
让我们重新来看图1所示的模型:
实际上,如果单纯从一个实时性任务自身出发来看,的确在实时性窗口内,任意时间完成事件的处理都是一样的;然而,通过前面的举例我们其实可以发现,当一个系统中存在多个实时性任务时,虽然一个实时性窗口内的任意时间对任务自己都是等价的,但越靠前的时间对“别人”来说是越宝贵的:
-
当你使用“越快越好”策略时,你不会有额外的收益,而实际上是走了别人的路,让人无路可走——典型的损人不利己; -
当你在别人需要的时候,在自己实时性得到保证的前提下,尽可能让出对你没有额外价值的靠前的时间,实际上是一种“利他主义”; -
当所有的任务都采用这种利他策略时,就变成了“人人为我,我为人人”的合作策略——这种情况下,如果数学证明整个系统一定存在一个方案来满足所有任务的实时性需求,那么利他策略一定能找到这样的解决方案。
作为一个系统开发者,我们显然是需要从全局考虑的,因此完全没有必要从单个实时性任务的自私视角来看问题,因此结论就变得更为直接:实时性窗口内越靠前的时间价值越高,从总体上来看“单纯”越快越好的策略对实时性是有害的。
为了验证另外一个极端“越慢越好(越靠后越好)”是否是正确的,我们不妨以同样的例子来推演一下,仅仅更新task_a()、task_b()和task_c()的执行策略:从“越快越好”变为“越慢越好”——这实际上意味着:
-
每一个事件处理任务都清楚的知道“距离事件发生已经过去了多长时间”; -
为了做到“卡着上课铃进教室”,不到最后时刻,绝对不执行任务处理。
图 6 过于谦让的后果……
如此谦让(浪费)了3ms以后,任务B终于决定下场——在执行了3ms任务处理后,成功的将随后的任务C逼上了绝路……随着A的沦陷,大型翻车现场成就达成……
【小结】
精选汇总 | 专栏 | 目录 | 搜索
精选汇总 | ARM、Cortex-M
精选汇总 | ST工具、下载编程工具
点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。
免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!