我正在Cortex-A9上使用多线程裸机C/Assembler应用程序。
我有一些共享变量,即多个线程使用的地址。为了执行变量值的原子交换,我使用LDRX
和STRX
。现在我的问题是,如果我需要LDRX
和STRX
每次访问这个变量之一,即使中断被禁用。
假设如下示例:
- 线程1使用
LDRX
和STRX
交换地址a的值 - 线程2禁用中断,使用正常的
LDR
和STR
来交换地址a的值,做一些不应该被中断的事情,然后再次启用中断。
如果线程1在线程2的LDRX
之后被中断会发生什么?线程1中的STRX
是否仍然认识到地址a上有访问,或者我是否必须在线程2中使用LDRX
和STRX
?
LDREX/STREX是芯片供应商必须实现的东西,希望符合arm规范。您可以并且应该获得关于该主题的arm文档,在这种情况下,除了arm和术语之外,您还应该获得amba- axis文档。
所以如果你有
ldrex thread 1
interrupt
ldrex thread 2
strex thread 2
return from interrupt
strex thread 1
在线程2 ldrex和strex之间没有修改内存位置,所以strex应该工作。但是在线程1 strex和先前的ldrex之间,对线程2 strex的位置进行了修改。所以在理论上,这意味着线程1 strex应该失败,你必须再次尝试你的线程1 ldrex/strex对,直到它工作。但这正是通过设计,您将在循环中不断尝试ldrex/strex对,直到成功为止。
但这都是实现定义的,所以你必须查看特定的芯片供应商、模型和rev,并做你自己的实验。例如,linux中的错误是ldrex/strex是一个无限循环,将其应用于不支持ldrex/strex的系统/情况,您将获得一个OKAY而不是EXOKAY,并且strex将永远失败,您将永远陷入无限循环(曾经想过我是如何知道所有这些的,必须在逻辑级别调试这个问题)。
首先,ARM文档表明,单处理器系统不需要独占访问支持,因此如果您在单核系统上触摸供应商特定的逻辑,ldrex/strex对可能无法工作。如果你的ldrex/strex仍然在arm逻辑(L1和可选的L2缓存)内,那么ldrex/strex对由arm而不是芯片供应商管理,所以你属于一组规则,如果这对触及arm核心之外的系统内存,那么你属于供应商规则。
最大的问题是ARM的文档在这个主题上非常不完整。根据哪个手册和在手册中你读它的地方,例如说,如果一些其他主已经修改了该位置,在你的情况下,它是相同的主,所以位置已经被修改,但因为它是由你的第二个strex应该成功。然后同样的文档说另一个独占读将监视器重置到一个不同的地址,那么如果它是同一地址的另一个独占读呢?
基本上你的问题是,如果两个对同一地址的独占写操作在没有独占读操作的情况下,第二次是否成功?非常好的问题……无论是在所有的arm内核中,还是在整个arm芯片世界中,我都看不到一个明确的答案。
ldrex/strex的底线不是完全特定于ARM核心,而是特定于芯片(供应商)。您需要做一些实验,以确保您可以在该系统(无论是否为单处理器)上使用该指令对。你需要知道ARM核心做什么(缓存),以及当排他性访问超出核心到供应商逻辑时会发生什么。
很抱歉我刚刚向dwelch抛出了一个"这是错误的"声明,但是我昨天没有时间写一个合适的答案。德韦尔奇对你问题的回答是正确的,但其中的一些部分至少有可能被误解。
简短的回答是,是的,您需要为两个线程禁用中断,或者为两个线程使用ldrex/strex。
但是要明确一件事:支持ldrex/strex在所有v6或更高版本的ARM处理器中是强制性的(v6M微控制器除外)。但是,对SWP的支持对于某些ARMv7处理器是可选的。
ldrex/strex的行为取决于您的MMU是否启用以及访问区域配置的内存类型和属性。为了使ldrex/strex能够正确运行,某些可能的配置将需要向互连控制器或RAM控制器添加额外的支持。
整个概念是基于本地和全局独占监视器的思想。如果在标记为不可共享的内存区域上操作(在单处理器配置中),处理器只需要关注本地监视器。
在多核配置中,相干区域使用在体系结构上被认为是全局监视器的东西进行管理,但仍然驻留在多核处理器中,并且不依赖于外部实现的逻辑。
现在,dwelch是正确的,因为围绕这一点有太多的"实现定义"选项。您所描述的序列在体系结构上是NOT保证工作的。该体系结构不要求str将本地(或全局)监视器从独占状态转换为打开状态(尽管在某些实现中可能会这样做)。
因此,在体系结构上安全的选项是:- 在两个上下文中都使用ldrex/strex。 在两个上下文中禁用中断。