操作系统内核运行原理
任务调度,抢占式内核,你真的懂吗?
最近在捣鼓一个智能空调面板的项目,用的是GD系列的国产芯片,上面跑FreeRTOS。本来以为就是把代码写好,下载进去跑起来就行。结果发现,程序跑是跑了,但有时候按键不灵敏,有时候温湿度数据更新慢半拍。折腾了好几天,最后才搞明白,问题出在任务调度上,根本不是硬件的问题。

一开始三个任务都是按顺序创建的:显示、按键、温湿度读取。我寻思着创建顺序有啥影响呢?后来才搞清楚,FreeRTOS的任务调度和创建顺序没关系,关键是看优先级。我给温湿度读取任务设了高优先级,其他两个是低优先级。按道理说,只要这个高优先级任务一就绪,就得马上运行。
系统时钟节拍设的是1ms,也就是每隔1毫秒就会进一次SysTick中断。这个中断里会调vTaskGetTickCount()更新时间,然后检查有没有任务等的时间到了。比如温湿度任务每次工作完就延时4ms,那它就会被系统放到等待表里,暂时不参与调度。
这时候就绪表里就剩两个低优先级任务,显示和按键,优先级一样。FreeRTOS处理这种情况是轮着来,叫时间片调度。显示任务先跑,1ms时间到了,SysTick中断进来,系统一看,哦该轮到下一个了,就把显示任务扔到就绪表队尾,把按键任务提到前面,然后做任务切换,按键任务就开始执行。
就这样来回切换,1ms一中断,看起来三个任务都在同时工作。但实际上CPU在任何一个瞬间,其实只在干一件事。只是切换得太快,人感觉不到。这就是所谓的“并发”,不是真正的同时运行。

关键的地方来了。等到第4个1ms节拍到来,温湿度任务等的4ms时间到了。系统时钟节拍服务发现这个任务等待超时了,立刻就把它从等待表里拉出来,加到就绪表里。这时候内核马上检查,就绪表里谁优先级最高?一看,哦那个高优先级的温湿度任务来了。
因为是抢占式内核,系统二话不说,哪怕按键任务才刚执行了0.1ms,也会立刻暂停它,保存它的所有寄存器状态,把CPU让给温湿度任务。这就是抢占。高优先级任务一来,低优先级的就得马上让位。
整个过程就像驾校练车,教练车只有一辆。VIP学员(高优先级任务)一回来,不管普通学员(低优先级任务)练到哪了,都得把车交出来。等VIP练完了,普通学员才能继续。这就是实时系统的意义,能保证重要任务及时响应。
任务控制块TCB里存着每个任务的所有信息,栈指针、优先级、状态啥的。每次切换的时候,内核就根据这些信息,把上一个任务的现场保存到它的栈里,再把下一个任务的现场从它的栈里恢复出来。这个过程叫上下文切换,就是换个人上场。
之前按键不灵敏,是因为我把按键扫描的时间设得太长,又没设合适的延时,导致它占着CPU不放。后来改成每扫描完一次就延时一下,让出时间片,问题就没了。温湿度数据延迟也是一样,它的周期是4ms,和1ms的节拍器配合得好好的。

整个系统就这么转着,哪个任务该等就等,该跑就跑。内核像个管家,管着就绪表和等待表两张名单,谁该上场谁该候着,安排得明明白白。定时器每响一次,它就出来看一眼,该调整就调整。
代码也没重写几行,就是把任务延时和优先级理清楚了。烧进去一试,所有功能都正常了。原来问题不在代码逻辑,在对内核运行原理的理解。以前光知道创建任务、启动调度,至于背后怎么调度的,稀里糊涂的。
现在算是搞明白了,操作系统的内核,核心就两件事:一是管理任务的状态,就绪、运行、等待;二是决定什么时候让哪个任务上CPU。靠的就是那个定时中断和抢占规则。看似复杂,拆开了看也没那么玄乎。
东西修好了,可以继续下个项目了。
