本文档介绍了 Arm Mbed OS RTOS 和线程安全机制,然后讨论将它们移植到新目标。
Mbed OS 5 中引入的主要改进之一是基于实时操作系统(RTOS)的新编程模型。一些早期版本的 Arm Mbed 已经为 RTOS 提供了可选支持。在版本 5 中,RTOS 支持是平台的标准功能,因此开发人员可以利用基于多线程的更灵活的编程模型。
与任何多线程环境一样,Mbed 开发人员需要使用各种同步原语来确保其代码不包含竞争条件或其他并发问题。他们还需要了解 Mbed OS 5 API 在使用它们时提供的线程安全性。这对于响应硬件中断服务例程(ISR)而运行的代码尤其重要,因为硬件中断服务例程需要仔细设计,以免损害整个系统的线程安全性。
Mbed OS 库包含内部同步,以提供各种级别的线程安全性。本文档描述了 Mbed OS 5 为构建线程安全应用程序提供的机制。
同步级别
Mbed OS 5 中的不同组件提供不同级别的同步:
提示: API 参考指示每个功能的同步级别。
标准库
使用完整版标准库时,所有受支持的工具链都是线程安全的:
注意: GCC 和 ARMCC 提供了较小的库变体。这些较小的版本不是线程安全的,使用它们的项目应始终只使用一个线程。
驱动程序
大多数驱动程序是线程安全下面列出了一些值得注意的例外;检查相关的手册页或 doxygen,了解有关所用驱动程序的更多具体细节。
中断安全的驱动程序:
未受保护的驱动程序:
HAL C API
HAL C API 是 Mbed OS 5 的移植层,不是线程安全的。开发人员通常不应直接使用此 API,而应使用更高级别的驱动程序和库。如果直接编程到 HAL C API,则您有责任将操作与适当的机制(例如互斥锁)同步。
同步机制
Mutex
Mbed RTOS C++ API 提供了互斥锁类,它是用于使代码线程安全的最简单的基元之一。使用互斥锁是保护对象数据的推荐方法,并且通过使用互斥锁使大多数常见的 Mbed API 成为线程安全的。
但是,有时简单的互斥锁不是实现线程安全的适当机制。特别是,不应在中断服务例程(ISR)中使用互斥锁。使用 ISR 的正确方法是不让它们在响应中断时进行任何实际处理。相反,中断应该向线程发送事件或消息;然后中断完成,线程被重新安排,随后,它将执行处理的线程。这允许线程在需要进行处理时安全地获取互斥锁。
RTOS 提供了几种将中断处理移动到线程上的机制。这些包括但不限于:
注意: 在 Mbed OS 5 中,如果您尝试在中断中使用互斥锁,则不会发生任何事情;无论锁是否实际空闲,锁定互斥锁的尝试都会立即成功。换句话说,如果在中断中获得互斥锁,则可以破坏线程安全机制并将竞争条件引入其他安全的代码段。未来版本的 Mbed OS 将提供警告并最终防止这种情况发生。
有关更多信息,请参阅 rtos/Mutex.h。
Atomics
Mbed OS 提供原子功能,使代码中断安全。如果必须从中断修改对象或数据结构,则可以使用这些原子函数来同步访问。
有关更多信息,请参阅 platform/critical.h。
关键部分
关键部分禁用中断以提供对资源的不间断访问,因此您可以使用关键部分来使代码中断安全。但是,如果可以,应该避免使用关键部分,因为它们必须快速执行,否则会导致系统不稳定。
注意:
有关更多信息,请参阅 platform/critical.h。
主要的 Mbed OS 库
mbed-tls
- 不受保护: 只要对其操作的对象进行了适当的保护,函数调用对任何线程都是安全的 - 请参阅 文档。编写线程安全代码时的其他注意事项
删除对象时,同步不会提供保护;删除对象时,也会删除保护它的互斥锁。这意味着删除对象时,必须确保使用它完成所有其他线程。
您需要使用相同的引脚同步对来自两个对象的硬件的访问。例如,如果在同一引脚上创建了两个 Serial 实例,则同时写入两个对象可能会导致不稳定。
将新平台移植到 Mbed OS 5 几乎与 Mbed 2 中的相同。通常,在 C HAL 层下运行的驱动程序不需要同步机制,因为这已经在更高级别提供。唯一的例外是函数 port_read,port_write,gpio_read 和 gpio_write,它们应该使用特定于处理器的 set 和 clear 寄存器,而不是执行读 - 修改 - 写序列。有关更多信息,请参阅 示例。
有关更多信息,请参阅 CMSIS-RTOS 教程。