|
1
6
TL:是的, LL/SC (STREX/LDREX)与禁用中断相比,可以通过重试使原子RMW可中断,从而改善中断延迟。
这可能是以吞吐量为代价的,因为显然在ARMv7上禁用/重新启用中断非常便宜(每个中断可能有1到2个周期)
非常 稀有的只有当中断在另一个中断处理程序的LL/SC中间出现时才出现。 不幸的是,像gcc这样的C11编译器对于单处理器系统或单线程代码没有特殊的case模式 . 因此,他们不知道如何使用代码生成器来利用这样一个事实,即在同一个内核上运行的任何东西都会在某一点上以程序顺序看到我们的所有操作,即使没有任何障碍。 (无序执行和内存重新排序的主要规则是,它保留了单线程或单核以程序顺序运行指令的假象。)
背靠背
单核CPU上的原子
之后
一
On the Godbolt compiler explorer
法学/理学学士
这是安全的,因为
从中断处理程序内部安全使用STREX/LDREX:ARM® Synchronization Primitives (2009年起)有一些关于管理LDREX/STREX的ISA规则的详细信息。运行LDREX会初始化“独占监视器”,以检测其他内核(或系统中的其他非CPU事物?我不知道)的修改。Cortex-M4是一个单核系统。 总是 测试代码时失败(因此陷入重试循环),这可能就是问题所在。
打断一下就行了
中止由LDREX启动的事务
看见 When is CLREX actually needed on ARM Cortex M7? 这和我要说的是一样的 在中断情况下,当线程之间不进行上下文切换时,通常不需要CLREX。 (有趣的事实:最近关于这个链接问题的一个回答指出Cortex M7(或者通常是Cortex M?)会在中断时自动清除监视器,这意味着在中断处理程序中永远不需要clrex。下面的推理仍然适用于带有不跟踪地址的监视器的旧单核ARM CPU, unlike in multi-core CPUs .) 但对于这个问题,你要换的东西 到 始终是中断处理程序的开始。你没有做先发制人的多任务。 只要STREX在低优先级中断中第一次失败,当您返回它时,就可以了。 这里就是这种情况,因为更高优先级的中断只有在成功执行STREX(或者根本没有执行任何原子rmw)之后才会返回。
所以我觉得即使不使用
如果在LDREX和STREX之间出现中断,则LL已将旧数据加载到寄存器中(可能还计算了一个新值),但由于STREX尚未运行,因此尚未将任何内容存储回内存。
当CPU已经在监控前一个LDREX时,为同一地址运行另一个LDREX看起来应该没有效果。对服务器执行独占加载 不同的 地址会将监视器重置为打开状态,但对于这个地址,它始终是相同的地址(除非在其他代码中有其他原子?) 然后(在做了一些其他事情之后),中断处理程序将返回,恢复寄存器并跳回低优先级中断的LL/SC循环的中间。
回到低优先级中断时,STREX将失败,因为高优先级中断中的STREX重置监视器状态。那很好,我们
需要
它可能会失败,因为它会存储与在FIFO中占据其位置的高优先级中断相同的值。这个
因此,我认为我们可以在任何地方都不使用CLREX,因为中断处理程序总是在返回到它们中断的内容中间之前运行到完成。他们总是从一开始就开始。 单作者版本
或者,如果没有其他东西可以修改该变量,则根本不需要原子RMW,只需要一个纯原子加载,然后是新值的纯原子存储。(
或者,如果没有任何其他线程或中断触及该变量,则不需要这样做
这和我们在非原子方面得到的asm是一样的
|
|
2
2
您的代码不是以“裸机”的方式编写的。那些“通用”原子函数不知道读取或存储的值是否位于内部存储器中,或者它可能是一个硬件寄存器,位于远离内核的某处,通过总线连接,有时通过写/读缓冲器连接。
在我看来,当您想以原子方式访问内存位置时,禁用中断就足够了。 PS stdatomic在裸机uC开发中的应用非常罕见。 保证M4 uC独占访问的最快方法是禁用和启用中断。
这两种指令只需额外花费2或4个时钟。 它保证了原子性,并且不提供不必要的开销 |
|
|
3
0
(来自 http://infocenter.arm.com/help/topic/com.arm.doc.genc007826/Barrier_Litmus_Tests_and_Cookbook_A08.pdf ,第6.2.1节“弱序消息传递问题”)。
在CPUI中,优化可以对上的指令重新排序
没有别的
性能影响很难估计(您必须对代码进行基准测试,无论有无测试)
|