0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RTOS多线程必须要MMU才行?

strongerHuang 来源:strongerHuang 作者:strongerHuang 2022-10-11 18:56 次阅读

前两天看到有人说:计算机的多线程,必须要有MMU才行,否则系统不能正常运行。

MMU:Memory Management Unit,即内存管理单元,它是一个“好东西”,在大型的操作系统中,起到了关键的作用。

但是,并不是所有操作系统都需要MMU才行,我们嵌入式中很多常用的RTOS(实时操作系统)没有MMU一样可以实现多线程。

只是RTOS实现的多线程相对大型操作系统要简单一点,其原理也要简单的多。

下面就来围绕RTOS给大家大家关于RTOS的多线程的内容。

多线程

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

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

比如处理器执行两个线程,处理器实际在两个线程之间来回切换,如下图:9a4bc2c6-4854-11ed-a3b6-dac502259ad0.png

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

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

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

//假设我们有两个整数:a和b

int c = a + b ;

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

# MIPS反汇编

LW V0, -32744(GP) # “a” 的值从RAM加载到寄存器V0

LW V1, -32740(GP) # 值“b” 从RAM加载到寄存器V1

ADDU V0, V1, V0 # a、b值相加,结果保存到寄存器V0中

SW V0, -32496(GP) # 寄存器V0的值存储在RAM中(变量c所在的位置)

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

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

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

9a61bd42-4854-11ed-a3b6-dac502259ad0.png

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

线程的堆栈

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

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

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

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

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

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

9a7050b4-4854-11ed-a3b6-dac502259ad0.png

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

9a895550-4854-11ed-a3b6-dac502259ad0.png

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

当内核决定将控制权切换到线程B时,它将执行以下操作:

将所有寄存器值保存到堆栈中(保存到线程A堆栈的顶部);

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

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

此时,你会看到:

9aa60c04-4854-11ed-a3b6-dac502259ad0.png

中断(ISR)抢占

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

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

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

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

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

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

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

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

中断堆栈

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

一般有两种方法:

使用被中断的线程堆栈;

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

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

9ab70950-4854-11ed-a3b6-dac502259ad0.png

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

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

每个线程的堆栈都应该包含以下内容:

线程自己的数据;

线程的上下文;

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

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

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

9ac71b92-4854-11ed-a3b6-dac502259ad0.png

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

好了,本文讲述了上面几种关于抢占,以及相关的内容,你学会了几点?

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 计算机
    +关注

    关注

    19

    文章

    6649

    浏览量

    84526
  • 多线程
    +关注

    关注

    0

    文章

    271

    浏览量

    19724
  • RTOS
    +关注

    关注

    20

    文章

    776

    浏览量

    118796
  • 内存管理
    +关注

    关注

    0

    文章

    162

    浏览量

    14056
  • MMU
    MMU
    +关注

    关注

    0

    文章

    91

    浏览量

    17940

原文标题:多线程必须要MMU才行?

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Java多线程的用法

    本文将介绍一下Java多线程的用法。 基础介绍 什么是多线程 指的是在一个进程中同时运行多个线程,每个线程都可以独立执行不同的任务或操作。 与单线程
    的头像 发表于 09-30 17:07 621次阅读

    Python多线程编程原理

    Python多线程类似于同时执行多个不同程序,但其执行过程中和进程还是有区别的,每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序
    发表于 11-22 14:01

    rtthread线程调度

    rtthread线程调度,RT-Thread多线程学习总结多线程是实时操作系统里面最重要的知识点之一,要学习RTOS多线程
    发表于 07-20 07:21

    多线程的过程程序

    1、多线程了解线程之前我们必须要先了解(程序—>进程—>线程)的过程程序:是一组计算机能识别和执行的指令,运行于电子计算机上,满足人们某种需求的信息化工具。进程:进程指正在运行的程序
    发表于 08-24 08:28

    linux多线程编程技术

    (process)中只允许有一个线程,这样多线程就意味着多进程。现在,多线程技术已经被许多操作系统所支持,包括Windows/NT,当然,也包括Linux。 为什么有了进程的概念后,还要再引入
    发表于 10-24 16:01 5次下载

    多线程好还是单线程好?单线程多线程的区别 优缺点分析

    摘要:如今单线程多线程已经得到普遍运用,那么到底多线程好还是单线程好呢?单线程多线程的区别又
    发表于 12-08 09:33 8w次阅读

    什么是多线程编程?多线程编程基础知识

    摘要:多线程编程是现代软件技术中很重要的一个环节。要弄懂多线程,这就要牵涉到多进程。本文主要以多线程编程以及多线程编程相关知识而做出的一些结论。
    发表于 12-08 16:30 1.2w次阅读

    C#多线程技术

    C#和.NET类库为开发多线程应用程序提供了很方便的支持,本章首先简要介绍.NET类库中的Thread类及各种线程支持,再通过示例说明线程使用中需要掌握的规则,最后论述线程同步时出现的
    发表于 04-23 11:32 14次下载

    RTOS多线程访问同一硬件(如UART)的方法

    RTOS多线程(任务)访问同一硬件(如UART)的方法
    的头像 发表于 03-12 11:28 4997次阅读

    通过多线程来实现ADC采集功能和OLED显示功能

    RTOS编程和裸机编程最大的区别就是RTOS可实现多线程管理,这是RTOS的最大优势。既然跑了操作系统,为何不用多线程实现ADC采集功能和O
    的头像 发表于 11-20 09:30 5375次阅读
    通过<b class='flag-5'>多线程</b>来实现ADC采集功能和OLED显示功能

    RT-Thread学习笔记 --(4)RT-Thread多线程学习过程总结

    多线程是实时操作系统里面最重要的知识点之一,要学习RTOS多线程必须(没错,是必须)要熟练掌握的内容,只有熟练掌握
    发表于 01-25 18:54 0次下载
    RT-Thread学习笔记 --(4)RT-Thread<b class='flag-5'>多线程</b>学习过程总结

    Java多线程永动任务 多线程异步任务项目解读

    1. 功能说明 2. 多线程任务示例 2.1 线程池 2.2 单个任务 2.3 任务入口 2.4 结果分析 2.5 源码地址 3. 写在最后 大家好,今天教大家撸一个 Java 的多线程永动任务
    的头像 发表于 10-19 11:46 790次阅读

    SpringBoot实现多线程

    SpringBoot实现多线程
    的头像 发表于 01-12 16:59 1292次阅读
    SpringBoot实现<b class='flag-5'>多线程</b>

    什么是线程安全?如何理解线程安全?

    多线程编程中,线程安全是必须要考虑的因素。
    的头像 发表于 05-30 14:33 1506次阅读
    什么是<b class='flag-5'>线程</b>安全?如何理解<b class='flag-5'>线程</b>安全?

    labview AMC多线程

    labview_AMC多线程
    发表于 08-21 10:31 23次下载