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

    文章

    8648

    浏览量

    361746
  • uart
    +关注

    关注

    22

    文章

    1156

    浏览量

    99944
收藏 人收藏

    评论

    相关推荐

    一文详解RTOS开发中的原子操作

    裸机开发与RTOS开发一个非常重要的区别在于多线程之间的消息传递和数据共享问题,然而在这中间变量的原子操作是一个非常重要的话题,不同的处理器架构和编译选项都可能生成不同的指令,从而影响到变量的
    发表于 11-17 09:43 1309次阅读

    多线程编程之四 线程同步

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

    Linux多线程线程同步

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

    基于51单片机的多线程操作系统 精选资料分享

    以STC89C52RC芯片为硬件平台,Keil5为编译平台,来实现一个简易的操作系统。实现一个多线程RTOS,前提是实现线程切换。毕竟,多线程
    发表于 07-20 07:55

    QNX环境下多线程编程

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

    基于单片机系统中的多任务多线程机制的实现

       首先要指出的是一点是,我们不是讨论嵌入式实时多任务操作系统RTOS)的设计。我们讨论的是,在不使用RTOS的控制系统中,如何体现多任务
    发表于 09-26 16:12 1832次阅读

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

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

    java多线程同步方法

    操作,一个取100块,一个存钱100块。假设账户原本有0块,如果取钱线程和存钱线程同时发生,会出现什么结果呢?取钱不成功,账户余额是100.取钱成功了,账户余额是0.那到底是哪个呢?很难说清楚。因此多线程
    发表于 09-27 13:19 0次下载

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

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

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

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

    Linux多线程同步

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

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

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

    RTOS多线程必须要MMU才行?

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

    多线程同步的几种方法

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

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

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