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

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

3天内不再提示

多线程RTOS系统:如何加速原子同步

要长高 来源:embedded 作者:Aaron Bauch 2022-06-02 18:19 次阅读

同步

原子操作的动机来自于在共享资源时需要同步两个或多个实体。一个简单的例子可能是基于多线程 RTOS 的系统中的两个线程,这两个线程都需要偶尔向它们共享的 UART 外围设备发送消息。

在操作中,一个线程可能会获得对 UART 的控制权并持有该控制权,直到其整个消息被发送。否则,如果另一个线程决定在第一个线程未完成时发送消息,这两个线程可能会通过 UART 发送替代字符,从而导致控制台端口出现一堆难以理解的乱码。

为了解决这个问题,我们可以定义一个资源,就像单个内存位置一样简单,它包含一个指示 UART 是忙还是可用的数据字。假设这个位置的 0 表示 UART 空闲,而 1 表示它正在使用中。

当线程 1 有消息要发送时,它会读取锁定字。它看到它是 0,所以它写一个 1 到这个位置。任何其他想要发送消息的线程都会发现这个锁或信号量包含一个 1,并且会等到它被清除后再尝试获取资源以供自己使用。

如果检查和设置锁的过程被中断,就会出现问题。

考虑以下情况:

任务 1 读取锁定字。

它找到包含零的单词。

任务 1 由于更高优先级的任务或导致其暂停的中断而停止。

当任务 1 被挂起时,任务 2 以更高的优先级运行。

任务 2 需要发送一条消息并读取它发现包含零的锁定字。

任务 1 将 1 写入锁定字,知道它现在拥有 UART 的唯一控制权,直到其消息被发送。

由于所需资源不可用,任务 2 释放控制权。

任务 1 继续运行,知道锁包含 0,将 1 写入锁字。

现在,任务 1 和任务 2 都确定它们对 UART 资源具有独特的控制权,并将交错地向其发送字符,因为他们看到它在逐个字符的基础上变得可用。

原子操作

解决这个问题需要一个原子操作,以确保检查和设置锁定字的完整事务在任何其他代理(即使具有更高优先级的代理)可以中断正在进行的关键操作之前完成。

原子操作只是以一个不间断的顺序完成的操作。即使这是一个复杂的事件序列。

对原子操作的支持内置于 C11 及更高版本等语言标准中。但是,用于在机器指令级别和硬件级别实现这一点的实际机制必须存在于 CPU 的指令集架构 (ISA) 和系统硬件实现中,以确保正确操作。

在上述情况下,任务 1 必须完成所有测试和设置锁的步骤,然后任何其他任务或实体才能访问内存中的锁字。

在单核系统中,这通常可以通过简单地在读取锁定字之前禁用所有中断并在写入锁定后重新启用它们来确保。通过这种方式,不会发生中断,因此不会导致内核在其测试和设置操作的中间抢占任务 1。

当然,在具有其他总线主控器的单核系统的情况下,例如 DMA 控制器和可以直接写入内存的外围设备,这可能会因这些其他总线主控器之一在错误的时间写入锁定值而被违反。但是,可以通过确保存储锁变量的内存不能被系统中的任何其他总线主控器访问来防止这种情况发生。

多核复杂性

现在我们看看在同一个芯片上有多个计算元素的情况,比如多核芯片,其中使用内存锁定来确保在不同内核上运行的线程也可以共享资源而不会相互破坏。

在这种情况下,我们无法阻止不同的总线主机访问锁定位置。这是因为锁定位置是每个内核必须能够读取和设置的位置,以确保正确共享公共资源(如上述 UART)。

现在我们必须确保一个核心一旦启动就可以完成其读-修改-写序列,在任何其他核心或总线主控器可以访问正在设置锁的内存位置之前。

Arm 架构的 8.1 版及更高版本中,为此添加了新的原子指令。我将把这个例子集中在新的指令上。一种这样的指令是 LDADD 指令及其变体。该指令从内存中读取一个值,将芯片上的一个寄存器中的值相加,然后将结果写回内存,同时保持内存总线,直到整个操作完成。

这样,系统可以保证没有其他总线主控器可以修改内存中的值,从而使两个主控器都认为他们拥有共享资源的所有权。

这段代码完成后,处理器可以检查读取的值,以验证它实际上是资源的唯一所有者,并且它的值对应于在操作开始之前可用的资源。

现实世界的影响

好消息是,如果您使用 RTOS 或操作系统在单核或多核线程环境中管理线程,这一切都在较低级别的系统代码中得到处理。然而,了解底层指令集和内存硬件必须设计为支持这些锁定机制以使这一切正常工作是有用的。如果这些机制设计不正确或被直接操纵寄存器误用,多个内核可能会无意中同时控制打算在使用时独占的资源。要调试这类情况,需要先进的多核调试功能,其中可以观察和控制在系统中的多个内核上运行的代码。

调试多核同步

多核调试器可以通过显示在多个内核或线程上运行的程序来帮助查找同步问题,以及根据另一个内核上的断点有选择地停止和启动内核的能力应该是确定这种机制问题的理想选择。

在图 1 中,我们可以在 IAR Embedded Workbench 中看到带有 4 个 CPU 的 NXP i.MX 8。所有核心都可以单独启动和停止。

poYBAGKYjiWAE2OSAADhRC2fgzE974.png

图 1:每个内核独立的调试器控制。(来源:IAR 系统)

图 2 显示了在不同 CPU 上运行的代码中使用多个断点并结合使用互斥锁(Arm 提供的示例):_mutex_acquire() 和 _mutex_release(),设置标志以阻止所使用对象的在素数计算中。

poYBAGKYjjGAYdxhAAPpeEG7Mr4459.png

图 2:在单个内核中使用互斥锁和断点。(来源:IAR 系统)

最常见的错误之一是滥用或未使用交叉触发接口 (CTI)。对于 Arm,CoreSight 交叉触发接口 (CTI) 通过交叉触发矩阵 (CTM) 连接到每个内核。CTI 使调试逻辑、ETM 跟踪单元和 PMU 能够相互交互并与其他 CoreSight 组件交互。这使得每个核心可以独立地停止和重置。不得不操纵“自制”的 CTI 变通方法,手动控制和停止内核,也许动态使用宏是一项不可能完成的任务。默认情况下,这应该并且需要由来自探针(CTI 接口信号)和软件调试端的良好调试器处理。图 3 显示了完全控制 CTI 的用例。

pYYBAGKYjkOAe3wmAACG35krBBM017.png

图 3:使用交叉触发接口 (CTI) 进行完全控制。(来源:IAR 系统)

一旦全部结合在一起,具有多核支持的调试器就可以在非对称和对称场景中控制内核,甚至可以组合在一起。图 4 显示了运行 4 个 Cortex-A53 和 1 个 Cortex-M4 的 NXP i.MX 8 设备。MCU 和 MPU 可以独立停止、监控和控制。虽然所有 4 个 Cortex-A53 内核或单个内核都从主会话运行,但可以在 Cortex-M4 合作伙伴端设置断点,并专注于可能正在运行整个设备的安全监视器的此应用程序。

poYBAGKYjliAPL7vAARd40o5hIQ446.png

图 4:在配备 4 个 Cortex-A53 和 1 个 Cortex-M4 的 NXP i.MX 8 设备上运行的多核会话。(来源:IAR 系统)

在应用程序中使用并行性和并发性旨在更有效地使用可用内核。然而,它的代价是增加了应用程序的复杂性,以及如何将源代码拆分成更小的部分以尽可能高效地运行。

概括

在单个芯片或系统中同步多个内核需要原子操作和执行这些操作的硬件。首次开发这种硬件/软件组合时,支持多核调试和观察的全功能调试器对于发现此类系统的问题至关重要。无法想象如何通过在整个代码中使用 print 语句来实现相同的控制,并使所有内容完美同步。每个开发人员都应该得到一个可以处理多核并完全控制所有线程的调试解决方案。IAR Embedded Workbench 及其调试器功能提供了这样一个工具,在开发和调试这些复杂系统时非常有用。

Aaron Bauch是IAR Systems的一名高级现场应用工程师,与美国东部和加拿大的客户合作。Aaron 曾为英特尔Analog Devices 和 Digital Equipment Corporation 等公司从事嵌入式系统和软件方面的工作。他的设计涵盖了广泛的应用,包括医疗仪器、导航和银行系统。Aaron 还以南新罕布什尔大学教授的身份教授了许多大学水平的课程,包括嵌入式系统设计。Bauch 先生拥有纽约州纽约市 The Cooper Union 的电气工程学士学位和哥伦比亚大学的电气工程硕士学位。

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

    关注

    134

    文章

    9059

    浏览量

    366928
  • uart
    +关注

    关注

    22

    文章

    1230

    浏览量

    101203
收藏 人收藏

    评论

    相关推荐

    Java多线程的用法

    能力。 什么是进程 是指正在运行的程序的实例。 每个进程都拥有自己的内存空间、代码、数据和文件等资源,可以独立运行、调度和管理。在操作系统中,进程是系统资源分配的最小单位,是实现多任务的基础。 Java多线程 Java
    的头像 发表于 09-30 17:07 932次阅读

    多线程编程之四 线程同步

    多线程编程之四 线程同步八、线程同步  虽然多线程能给我们带来好处,但是也有不少问题需要解决
    发表于 10-22 11:43

    Linux多线程线程同步

    pthread_mutex_lock先加锁,操作完之后pthread_mutex_unlock再解锁。5、线程同步条件变量:使用条件变量可以以原子方式阻塞线程,直到某个特定条件为真为
    发表于 12-08 14:14

    QNX环境下多线程编程

    介绍了QNX 实时操作系统多线程编程技术,包括线程同步的方法、多线程程序的分析步骤、线程基本
    发表于 08-12 17:37 30次下载

    多线程与聊天室程序的创建

    多线程程序的编写,多线程应用中容易出现的问题。互斥对象的讲解,如何采用互斥对象来实现多线程同步。如何利用命名互斥对象保证应用程序只有一个实例运行。应用
    发表于 05-16 15:22 0次下载

    设计多线程和多核系统

    如果您的微控制器应用程序需要处理数字音频,请考虑采用多线程方法。使用多线程设计方法可以使设计者以简单的方式重用其部分设计。
    发表于 08-14 15:42 9次下载
    设计<b class='flag-5'>多线程</b>和多核<b class='flag-5'>系统</b>

    基于多线程环境下值的递增操作--原子操作

    因此在多线程环境中对一个变量进行读写时,我们需要有一种方法能够保证对一个值的递增操作是原子操作——即不可打断性,一个线程在执行原子操作时,其它线程
    的头像 发表于 01-10 11:16 6151次阅读
    基于<b class='flag-5'>多线程</b>环境下值的递增操作--<b class='flag-5'>原子</b>操作

    Linux多线程同步

    overflow的问题。) 并发多线程相当于一个并发(concunrrency)系统。并发系统一般同时执行多个任务。如果多个任务可以共享资源,特别是同时写入某个变量的时候,就需要解决同步
    发表于 04-02 14:47 413次阅读

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

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

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

    RTOS编程和裸机编程最大的区别就是RTOS可实现多线程管理,这是RTOS的最大优势。既然跑了操作系统,为何不用
    的头像 发表于 11-20 09:30 5989次阅读
    通过<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>学习过程总结

    RTOS多线程必须要MMU才行?

    的作用。 但是,并不是所有操作系统都需要MMU才行,我们嵌入式中很多常用的RTOS(实时操作系统)没有MMU一样可以实现多线程。 只是RTOS
    的头像 发表于 10-11 18:56 2364次阅读

    多线程同步的几种方法

    多线程同步是指在多个线程并发执行的情况下,为了保证线程执行的正确性和一致性,需要采用特定的方法来协调线程之间的执行顺序和共享资源的访问。下面
    的头像 发表于 11-17 14:16 1129次阅读

    多线程如何保证数据的同步

    多线程编程是一种并发编程的方法,意味着程序中同时运行多个线程,每个线程可独立执行不同的任务,共享同一份数据。由于多线程并发执行的特点,会引发数据同步
    的头像 发表于 11-17 14:22 1164次阅读

    mfc多线程编程实例

    (图形用户界面)应用程序的开发。在这篇文章中,我们将重点介绍MFC中的多线程编程。 多线程编程在软件开发中非常重要,它可以实现程序的并发执行,提高程序的效率和响应速度。MFC提供了丰富的多线程支持,可以轻松地实现
    的头像 发表于 12-01 14:29 1453次阅读