由于我的编译器仍然不支持c ++ 11和std :: atomic,因此我不得不通过ldrex-strex对手动实现它。

我的问题是:用ldrex和strex'以原子方式'读写-修改-写入int64_t的正确方法是什么?

像这样的简单解决方案似乎不起作用(STREXW之一始终返回1):

volatile int64_t value;
int64_t temp;

do
{
    int32_t low = __LDREXW( (uint32_t *)&value );
    int32_t high = __LDREXW( ((uint32_t *)&value)+1 );

    temp = (int64_t)low | ( (int64_t)high<<32);
    temp++;

} while( __STREXW( temp, (uint32_t *)&value) |  __STREXW( temp>>32, ((uint32_t *)&value)+1) );


关于手册中指向不同地址的多个顺序LDREX或STREX指令,我找不到任何东西,但在我看来,应该允许使用它。

否则,在某些情况下,多个线程将无法更改两个不同的原子变量。

最佳答案

这将永远无法工作,因为您不能以这种方式嵌套互斥。在实现方面,Cortex-M3本地专用监视器甚至不跟踪地址-the exclusive reservation granule is the entire address space-因此,单独跟踪每个单词的假设已经无效。但是,您甚至不需要考虑任何实现细节,因为该体系结构已经明确排除了背对背strex


如果在没有插入LDREX的情况下执行了两条STREX指令,则第二条STREX返回状态值1。这意味着:


在给定的执行线程中,每个STREX必须具有与之关联的先前LDREX。
每个LDREX都不必具有后续的STREX。



由于Cortex-M3(通常是ARMv7-M)没有像ARMv7-A这样的ldrexd,因此您要么必须使用单独的锁来控制对变量的所有访问,要么仅禁用围绕read-修改-写入。如果有可能,最好首先重新设计不需要原子64位类型的内容,因为相对于同一内核上的其他线程,您仍然只能实现原子性-您根本无法制造64位类型从外部代理(如DMA控制器)的角度来看,位操作是原子的。

07-24 09:44