简体   繁体   English

ARM Cortex M3上的Atomic int64_t

[英]Atomic int64_t on ARM Cortex M3

Since my compiler still doesn't support c++11 and std::atomic, I'm forced to implement it manually via ldrex-strex pair. 由于我的编译器仍然不支持c ++ 11和std :: atomic,我不得不通过ldrex-strex对手动实现它。

My question is: what is the correct way to 'atomically' read-modify-write int64_t with ldrex and strex? 我的问题是:用ldrex和strex“原子地”读取 - 修改 - 写入int64_t的正确方法是什么?

Simple solution like this doesn't seem to work (one of STREXW returns 1 all the time): 像这样的简单解决方案似乎不起作用(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) );

I couldn't find anything about several sequential LDREX or STREX instructions pointing to different addresses in the manual but it seemed to me that it should be allowed. 我找不到关于指向手册中不同地址的几个连续LDREX或STREX指令的任何内容,但在我看来应该允许它。

Otherwise multiple threads would not be able to change two different atomic variables in some scenarios. 否则,在某些情况下,多个线程将无法更改两个不同的原子变量。

This will never work, because you cannot nest exclusives that way. 这将无法工作,因为您无法以这种方式嵌套。 Implementation-wise, the Cortex-M3 local exclusive monitor doesn't even keep track of an address - the exclusive reservation granule is the entire address space - so the assumption of tracking each word separately is already invalid. 实现方面,Cortex-M3本地专用监视器甚至不跟踪地址 - 独占预留颗粒是整个地址空间 - 因此单独跟踪每个单词的假设已经无效。 However, you don't even need to consider any implementation details, because the architecture already explicitly rules out the back-to-back strex : 但是,您甚至不需要考虑任何实现细节,因为该体系结构已经明确排除了背对背strex

If two STREX instructions are executed without an intervening LDREX the second STREX returns a status value of 1. This means that: 如果在没有插入LDREX的情况下执行两条STREX指令,则第二个STREX返回状态值1.这意味着:

  • Every STREX must have a preceding LDREX associated with it in a given thread of execution. 每个STREX必须在给定的执行线程中具有与之关联的先前LDREX。
  • It is not necessary for every LDREX to have a subsequent STREX . 每个LDREX都不必具有后续STREX。

Since Cortex-M3 (and ARMv7-M in general) doesn't have ldrexd like ARMv7-A, you'll either have to use a separate lock to control all accesses to the variable, or just disable interrupts around the read-modify-write. 由于Cortex-M3(以及一般的ARMv7-M)没有像ARMv7-A那样的ldrexd ,因此您必须使用单独的锁来控制对变量的所有访问,或者只是禁用读取 - 修改周围的中断 -写。 If at all possible it would really be better to redesign things not to need an atomic 64-bit type in the first place, since you'd still only achieve atomicity with respect to other threads on the same core - you simply cannot make any 64-bit operation atomic from the point of view of an external agent like a DMA controller. 如果可能的话,首先重新设计不需要原子64位类型的东西真的会更好,因为你仍然只能在同一个核心上实现相对于其他线程的原子性 - 你根本就不能做任何64从外部代理(如DMA控制器)的角度来看,位操作原子。

I'd just look at how gcc does it, and use the same instruction sequences. 我只看看gcc是如何做到的,并使用相同的指令序列。

gcc 4.8.2 claims to implement std::atomic<int64_t> with is_lock_free() returning true, even with -mcpu=cortex-m3 . gcc 4.8.2 声称实现std::atomic<int64_t>is_lock_free()返回true,即使使用-mcpu=cortex-m3 Unfortunately, it doesn't really work. 不幸的是,它并没有真正起作用。 It makes code that doesn't link or doesn't work, because there is no implementation of the helper functions it tries to use . 它使得代码不链接或不起作用,因为它没有实现它试图使用的辅助函数 (Thanks @Notlikethat for trying it out.) (感谢@Notlikethat试用它。)

Here's the test code I tried . 这是我试过的测试代码 See an old version of this answer if that link is dead. 如果该链接已死,请查看此答案的旧版本。 I'm leaving this answer around in case the idea is useful for anyone in related cases where gcc does make useful code. 我将离开这个答案,以防这个想法对gcc 确实有用的代码的相关情况下的任何人都有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM