当前位置:首页 > > strongerHuang
[导读]操作系统对于初学者来说是一个很神秘的东西,里面很多原理摸不清楚,导致还没入门就放弃了。本文就来从底层开始,详细讲述了抢占式操作系统(大多数RTOS)的抢占原理。

关注+星标公众,不错过精彩内容

作者 | strongerHuang
微信公众号 | strongerHuang

操作系统对于初学者来说是一个很神秘的东西,里面很多原理摸不清楚,导致还没入门就放弃了。

本文就来从底层开始,详细讲述抢占式操作系统(大多数RTOS)的抢占原理。

包含:
  • 线程基础原理

  • 线程之间抢占

  • 中断抢占线程

  • 中断抢占中断


strongerHuang

1

运行多个线程


1.单核“单线程

严格来说,单核处理器一次只能执行一条指令,也就是说只能“单线程(当然,多核处理器就不一样)


为了在单核处理器上运行多个线程,我们实际上需要定期在线程之间进行快速切换,以便用户感觉多个线程在并行运行。


比如处理器执行两个线程,处理器实际在两个线程之间来回切换,如下图:


2.处理器在线程之间切换,它是如何做到的?


我们说的单核处理器是“单线程的,它有一组寄存器,我们就叫这组寄存器属于一个“线程


例如,计算两个数字的总和时:

//假设我们有两个整数:a和bint c = a + b ;


实际发生的情况如下所示(当然,它取决于的MCU类型,但总体思路是相同):

# MIPS反汇编:
LW V0, -32744(GP) # "a" 的值从RAM加载到寄存器V0LW V1, -32740(GP) # 值"b" 从RAM加载到寄存器V1ADDU V0, V1, V0 # a、b值相加,结果保存到寄存器V0中SW V0, -32496(GP) # 寄存器V0的值存储在RAM中(变量c所在的位置)


你会发现上面执行了4个动作,但是抢占式操作系统可以在任何时候抢占另一个线程,包括在这4个动作之间。


假如在这过程中有其他线程抢占了,其他线程同样抢占了当前线程V0、 V1,如果不对V0、 V1进行保存,那么下次回来执行当前线程,结果就会出错。


所以,针对当前这种问题,我们就需要在切换线程之前,对V0、 V1的数值进行保存,当下次切换到当前线程,再恢复V0、 V1的数值,大致流程如下:


大概意思就是:当我们需要从一个线程切换到另一个线程时,内核获得控制权,执行必要的内务处理(至少要保存和恢复寄存器值),然后将控制权转移到下一个线程以运行。


strongerHuang

2

线程的堆栈


上面说的抢占位置,到底在哪里,每个线程保存在哪个寄存器值中?这就是线程的堆栈的内容。

在有MMU的操作系统中,(用户的)线程堆栈可以按需动态增长:线程需要的堆栈空间越多,线程堆栈就越多(如果内核允许)

但是,我们一般的MCU却没有MMU这个“高端”的东西,所有RAM都静态映射到地址空间。因此,每个线程都会有用于堆栈的RAM空间,如果线程使用的RAM超过堆栈的数量,则会导致内存溢出或细微的错误。(实际上,每个线程的堆栈空间只是一连续数组空间)。

因此,当我们决定为每个线程分配多少堆栈时,我们只是估计可能需要多少堆栈,但是具体多少可能不是很清楚。

比如,如果这是一个具有多层嵌套调用的GUI线程,则可能需要数个千字节,但如果它是一个流水灯的小线程,则可能几十字节就足够了。

假设我们有三个线程,它们的堆栈消耗如下:



如上面所述,每个线程的寄存器值都保存在线程的堆栈中。线程的寄存器值集称为线程的“上下文”。如下图所示 (线程A为在正在执行的“活动线程”)


请注意,在正在执行的线程A的上下文没有保存在堆栈中,堆栈指针指向线程A用户数据的顶部,并且当前处理器的寄存器专用于线程A。

当内核决定将控制权切换到线程B时,它将执行以下操作:
  • 将所有寄存器值保存到堆栈中(保存到线程A堆栈的顶部);

  • 将堆栈指针切换到线程B的堆栈顶部;

  • 从堆栈(从线程B的堆栈顶部)恢复所有寄存器值;


此时,你会看到:


strongerHuang

3

中断(ISR)抢占


上面在执行过程中,或进行上下文切换时,还可能会涉及到一个非常重要的内容:中断

MCU通常具有外设:TIM、UART、 SPI、 CAN等,它们随时都能发生重要事件以触发中断。

中断条件是当当前正在执行的线程暂停时,处理器在一段时间内执行其他操作(Handles Interrupt),然后返回。中断可能随时触发,我们应该做好处理的准备。

中断处理程序称为ISR(中断服务程序):
中断可能具有不同的优先级,例如,如果触发了一些低优先级的中断,则当前正在执行的线程将暂停,并且ISR会获得控制权。然后,如果触发了某个高优先级中断,则当前正在执行的ISR将再次暂停,并为该高优先级中断运行一个新的ISR。

这样一来,完成后,控制权将返回到第一个ISR,并且在完成时,也会恢复被中断的线程。

重要的关键代码:
在线程活跃过程中,如果有重要的事情“关键的代码”,在这过程中如果中断发生,很容易导致意想不到的结果。

这部分关键的代码,我们需要要保护起来,通常我们的做法就是:在之前“关键代码”之前禁用全局中断,执行完之后,开始全局中断。

有点需要注意:
关闭全局中断,此时就不会相应中断,所以,“关键代码”不能太长。

strongerHuang

3

中断堆栈


在上面说到一点,高优先级中断抢占低优先中断,就会出现一个问题:低优先级的代码需要和线程一样,用于保存数据的堆栈。

一般有两种方法:
  • 使用被中断的线程堆栈;

  • 为中断使用单独的堆栈空间;


1.使用被中断的线程堆栈
如果使用被中断的线程堆栈,就类似如下图:


这种情况存在你一个严重的问题,你知道是什么吗?

频繁中断,或者中断较多,线程自身的堆栈空间就会很快被使用完。

每个线程的堆栈都应该包含以下内容:
  • 线程自己的数据;

  • 线程的上下文;

  • 用于执行最坏情况的ISR的数据。


因此,我们就需要换一种方法,为为所有ISR中断开辟单独的堆栈空间。

2.为中断使用单独的堆栈空间


为中断使用单独的堆栈空间大致如上图所示。

好了,本文讲述了上面几种关于抢占,以及相关的内容,你学会了几点,又有几点没懂,欢迎留言讨论。


------------ END ------------

推荐阅读:

什么是自由软件?

几种特殊的函数宏封装方式

Keil MDK如何将变量存储在指定内存地址


关注 微信公众号『strongerHuang』,后台回复“1024”查看更多内容,回复“加群”按规则加入技术交流群。


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


点击“ 阅读原文 ”查看更多分享,欢迎点分享、收藏、点赞、在看。

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭