Cortex M3支持一对有用的操作操作(在许多其他机器中也是常见的),分别称为“ Load-Exclusive”(LDREX)和“ Store-Exclusive”(STREX)。从概念上讲,LDREX操作执行加载,还设置了一些特殊的硬件来观察加载的位置是否可能被其他东西写入。对最后一个LDREX所使用的地址执行STREX只会导致该地址只在没有其他写操作时才被写入。如果发生存储,则STREX指令将向寄存器加载0;如果中止,则将向寄存器加载1。
请注意,STREX通常是悲观的。在许多情况下,即使实际上未触摸过相关位置,它也可能决定不执行商店。例如,LDREX和STREX之间的中断将导致STREX假定正在监视的位置可能已命中。因此,通常最好将LDREX和STREX之间的代码量减到最少。例如,考虑如下内容:
内联void safe_increment(uint32_t * addr)
{
uint32_t new_value;
做
{
new_value = __ldrex(addr)+ 1;
} while(__ strex(new_value,addr));
}
编译成以下内容:
; 假设R0保留了相关地址;r1丢了
lp:
ldrex r1,[r0]
加r1,r1,#1
strex r1,r1,[r0]
cmp r1,#0; 测试是否非零
bne lp
..代码继续
在代码执行的绝大多数时间里,LDREX和STREX之间不会发生任何事情来“打扰”它们,因此STREX将成功而无事。但是,如果在LDREX或ADD指令之后立即发生中断,则STREX将不会执行存储,而是代码将返回以读取[r0]的值(可能已更新)并计算新的递增值基于此。
使用LDREX / STREX来形成诸如safe_increment之类的操作,不仅可以管理关键部分,而且在许多情况下都可以避免需要它们。