程序小白
认证:优质创作者
所在专题目录 查看专题
小小调度器——调度器核心的纯C实现
小小调度器——原来C代码还能这么写,原作者没少挨打吧!
小小调度器——开局default,优雅总藏于细节之中
作者动态 更多
RT-Thread驱动之路: Studio 挂载通用SPI flash④
4天前
RT-Thread驱动之路: Studio初始化SPI总线③
1星期前
RT-Thread驱动之路:Studio修改时钟篇②
2星期前
RT-Thread驱动之路: Studio硬件移植篇①
2星期前
RT-Thread驱动之路:stm32设备驱动开发之HWTIMER开发①
12-02 15:42

小小调度器——开局default,优雅总藏于细节之中

      有时候技术人员之间的差异微乎其微,但就是这微乎其微的差异积少成多,让我们与大牛之间的距离越来越远,当你开始在意这些细节而不是只关注成长的速度的时候,时间会告诉你当前版本的答案,技术的积累会产生难以想象的质变。大鹏一日同风起,然后一直起!起!起!(扯远了...回归主题)。

      会用和看懂是两个概念,假如你不赶时间的话,我愿用我蹩脚的解释,带你去看看作者的匠心独具。先上第一段热乎的代码:

      语言的尽头并不是C语言,机器无法执行一段C代码,她需要经编译,汇编等等操作最终形成可执行的机器码,当然我们是看不懂的,所以我们要理解,C语言首先要变成汇编代码,那么一条语句就可能编程好几句。

      当你从裸机编程切换到OS调度机制的时候,本质上来讲比单纯的裸机,CPU需要执行的代码更多更复杂了,机器的性能相对是降低了,为了尽量降低这种额外的开销,于是就出现了开局default的操作,这完全是站在机器的角度上选择结果,软件少一次的case判断,变成汇编语言就是可以少执行好几条语句,节省掉多个机器周期。


      接下来:让我们看一下两种运行任务的方式:

//运行任务
#define RunTask(TaskName,TaskID)  
do 
{ 
	if (timers[TaskID]==0) 
	{ 
		TASK d=TaskName(); 
		while(timers[TaskID]!=d) 
		timers[TaskID]=d;
	} 
} while(0);
//运行任务,前面的任务优先保证执行
#define RunTaskA(TaskName,TaskID)
do 
{ 
	if (timers[TaskID]==0) 
	{ 
		TASK d=TaskName(); 
		while(timers[TaskID]!=d) 
		timers[TaskID]=d;
		continue;
	} 
} while(0);

    先看下任务是如何运行的,先判断该任务对应的阻塞时间是否到达:

    1. 没到达的情况下,不运行任务,结束执行。

     2.时间到,timers倒计时为0,执行任务,并返回阻塞时间,第一个细节操作来了,先判断timers是否等于返回的阻塞时间,如果不等于则进行赋值,这里是不是多此一举,不用判断直接赋值多好,去掉while判断。你能这么想是因为你站在程序员的角度上,换一个角度,你站在机器的角度上来考虑问题,while判断和赋值操作的运行时间,假定赋值操作需要更多的执行时间开销,那么加一条while判断,再相等的情况下,是否就不需要执行赋值操作了,可以节省更多的操作时间,二当需要赋值的情况下,可能也就加一条简单的判断操作,我是这样的理解的,当然也可能不对,只是给你提供一条思路。

      对比任务和函数的区别:函数的返回值一般给到的是变量,作为函数执行的输出(当然是纯软的情况下,有硬件参与的情况下,更多的是硬件对应的执行动作),任务的返回值的意义是:阻塞时间,将值记录到任务对应的timers数组中,提供给任务框架进行计时操作。

      RunTask和RunTaskA的最大区别,就是continue的操作,执行完任务后,理论上任务返回的阻塞时间可以是任意值,当返回值为0时,代表着任务并未阻塞,这个是带有continue操作的任务将会重新运行该任务,也就是TaskA优先保证执行。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 1
收藏 2
关注 141
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧