ARM中的关键部分

Dar*_*bik 6 c arm bare-metal critical-section

我在实现AVR系列处理器的关键部分方面经验丰富,您所做的只是禁用中断(当然有内存屏障),执行关键操作,然后重新启用中断:

void my_critical_function()
{
   cli();  //Disable interrupts
   // Mission critical code here
   sei();  //Enable interrupts
}
Run Code Online (Sandbox Code Playgroud)

现在我的问题是:

这种简单的方法是否也适用于处理器的ARM体系结构?我听说过处理器在指令和其他黑魔法上做了先见之事,并且主要想知道这些类型的事情是否会对关键部分的这种实现产生问题.

coo*_*sed 12

假设您使用的是Cortex-M处理器,请查看C语言中提供的LDREXSTREX指令,这些指令可通过CMSIS(Cortex微控制器软件接口标准)提供的宏__LDREXW()__STREXW()宏来实现.它们可用于构建极其轻量级的互斥机制.

基本上,

data = __LDREXW(address)
Run Code Online (Sandbox Code Playgroud)

data = *address除了在CPU中设置"独占访问标志"之外,它的工作方式类似.完成操作数据后,使用将其写回

success = __STREXW(address, data)
Run Code Online (Sandbox Code Playgroud)

*address = data如果仍然设置了独占访问标志,那只会像写入一样成功.如果它确实成功写入,那么它也会清除标志.成功时返回0,失败时返回1.如果STREX失败,您必须返回LDREX并再试一次.

对于共享变量的简单独占访问,不需要任何其他内容.例如:

do {
  data = LDREX(address);
  data++;
} while (STREXW(address, data));
Run Code Online (Sandbox Code Playgroud)

关于这种机制的有趣之处在于它实际上是"最后来的,先到先得的"; 如果这个代码被中断,中断使用LDREXSTREX时,STREX中断将成功,(低优先级)的用户代码将不得不重试.

如果您正在使用操作系统,则可以使用相同的基元来构建"正确的"信号量和互斥量(例如,参见本应用笔记); 但是如果你使用的是OS,你可能已经可以通过它的API访问互斥体了!

  • 太酷了......我实际上正在用 C++ 创建我自己的原子数据类型(使用模板包装器),我可以将其提供为另一个后端,以便我可以混合和匹配实现...... (2认同)
  • 上述使用 ldrex 和 strex 指令的方法是有效的,并且它是保护关键部分的最佳方法。但如果您想通过禁用和重新启用中断来保护临界区,则应在禁用中断之前添加内存屏障指令。该指令告诉 CPU 从禁用中断的角度停止乱序执行。如果没有屏障指令,代码可能不会按预期运行。这仅适用于像 cortex-M 这样的处理器,它会重新排序指令以获得更好的性能。 (2认同)

P__*_*J__ 4

ARM 架构非常广泛,据我了解,您可能指的是 ARM Cortex M 微控制器。

您可以使用这种技术,但许多 ARM uC 还提供更多技术。由于我确实知道实际的硬件是什么,所以我只能给你一些例子:

  1. 位带区域。在此内存区域中,您可以以原子方式设置和重置位。
  2. 硬件信号量(STM32H7)
  3. 硬件 MUTEX-es(某些 NXP uC)

等等等等