当前位置: 首页 > >

这段代码不讲武德,劝你耗子尾汁

发布时间:

来源:公众号【鱼鹰谈单片机】


作者:鱼鹰Osprey


ID ??:emOsprey


动态数组???

不知道你是否听说过 C99 有一个动态数组的特性,也就是说,数组大小可以根据需要动态的变化。


我们都知道,在 C89 模式下,数组的声明只能是这样:



但到了 C99,数组的大小可以用变量代替,根据需要变化:



有些人为了尝鲜或者为了使用方便,可能会在程序中写上类似的代码。


一般情况下,代码运行很正常,没有一点问题。


但在运行时间需要严格控制的情况下,这段代码就不讲武(码)德了。


防出去了昂

我们都知道,嵌入式系统的一大好处就是运行时间可控,是实时的系统,所以它可以做一些高实时性的工作,比如控制、采样等。


就拿采样来说,一般都会要求采样率,比如 100Hz、10Hz,换算到时间单位,就是需要 10 毫秒、100毫秒读取一次数据,这个数据可能是内部寄存器(比如ADC),也可能是外部的器件通过 I2C、SPI等总线获取,而一般来说,这些总线的通信时间是稳定的、可控的。


但是有一天,你发现你的 SPI 驱动程序运行时间变得不再可控,它有时50us 完成一次数据的采集,有时需要 1 ms才完成,总之没有规律可循,唯一的规律就是,当系统全面开始工作时,这个时间大部分在 1 ms 以上,只有很少几次是几十微秒就完成了执行。


在 10 Hz 采样率下,1 ms 误差也不算太大,但当在 100 Hz采样时,时间误差就是 10%,不可忽略


你仔仔细细的查看了实现代码,发现就是简单的 SPI 通信,基本上都是判断、赋值操作,还有就是使用循环等待标志位(使用硬件 SPI),。


(或许你会怀疑循环等等标志代码导致了时间的不确定,但我的第一直觉告诉我不是它,因为 SPI 的通信时间是可控的(只要器件正常,从机一定会返回数据),STM32F1 系列的硬件 SPI 通信鱼鹰也用了五六年,不应该有问题才对)


这些我全部防出去了昂(甚至鱼鹰都考虑到线程执行可能受到中断的影响,特地在问题代码执行期间禁止了中断)。


没办法,我只能停停,放下源码本身的分析,拿出了杀手锏:《KEIL 下如何准确测量代码执行时间?》开始对问题代码进行时间测量。


有备而来

经过几番测量,很快昂,定位到类似下面的代码:



发现竟然在52到57行之间花费了大量时间。就一些局部变量的定义,唯一和传统写法不同的是使用了动态数组,怎么会花费这么多时间?


按照传统写法,这里应该使用固定大小的数组。


我大意了啊,没有闪,当时移植这份代码的时候就留意到了这个另类写法,当时还特地看了一下实现,但最终还是栽在了这里。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ??? ? ??


这段代码是乱打(写)的吗?他可不是乱打(写)的,格式清晰、移植方便、还有各种异常处理,明显有备而来。


来、骗,来、偷袭我这经验丰富的老同志。


这好吗?这不好,我劝他耗子尾汁。


寻根问底

事实上,如果对时间要求不是很高的话,这段代码不会有任何问题,它的基本读取功能是没有任何问题的,只是说它的执行时间很不稳定,有的时候几十微秒就可以执行完毕,有时候可能需要几毫秒时间,还有极端的可能是直接死机(Hardfault)!


那么动态数组是如何实现的,或者说它的本质是什么呢?


本质就是使用 malloc 函数申请堆空间(在 rt-thread 中又会调用 rt_malloc),然后在离开函数前使用 free 函数释放堆空间。


可以查看汇编确认:




看到这里,你也就知道为什么会出现之前的现象了吧。


系统未完全运行前,很少有线程申请堆空间,所以执行时间比较稳定,因为它能快速的找到合适的内存块,一旦系统里所有线程正式工作了,涉及到大量的内存申请与释放,有大量的内存碎片,也就不容易找到合适的内存,这样执行时间也就不稳定了,这对于实时要求高的功能是一个灾难。


所以,如果你的功能不要求实时性的话,使用动态数组是可以的,一旦你的功能要求实时性,那么使用静态数组才是更好的选择(如果使用静态数组,一定要注意使用范围,最好加上断言机制),如果代码是在中断执行,rt-thread系统中,则必须使用静态数组,否则 rt_malloc 无法正常执行(断言失败)。


你防住了吗?


推荐阅读:


嵌入式系统优先级详解


KEIL 调试经验总结


线程CPU使用率到底该如何计算?


许久以后,你会感谢自己写的异常处理代码


终极串口接收方式,极致效率


延时功能进化论(合集)


如何写一个健壮且高效的串口接收程序?


打了多年的单片机调试断点到底应该怎么设置?| 颠覆认知


-THE END-



如果对你有帮助,记得转发分享哦


微信公众号「鱼鹰谈单片机」


每周一更单片机知识



长按后前往图中包含的公众号关注



友情链接: