TL; DR:我需要等效于C11的atomic_load
的Microsoft C(而非C++)。有人知道正确的功能是什么吗?
我有一些使用原子的漂亮标准代码。就像是
do {
bar = atomic_load(&foo);
baz = some_stuff(bar);
} while (!atomic_compare_exchange_weak(&foo, &bar, baz));
我试图弄清楚如何使用MSVC处理它。 CAS很容易(
InterlockedCompareExchange
),但是atomic_load
却被证明比较麻烦。也许我缺少了一些东西,但是Synchronization Functions list on MSDN似乎没有任何内容可以简单加载。我唯一能想到的就是
InterlockedOr(object, 0)
之类的东西,它将为每个负载生成一个存储(更不用说围栏了)……只要变量是 volatile 的,我认为只读取值是安全的,但是如果我这样做,Visual Studio的code analysis功能会发出一堆C28112警告(“通过互锁函数访问的变量(foo)必须始终可以通过互锁功能进行访问。”)。
如果简单阅读确实是正确的方法,我想我可以用类似的方法使那些人沉默
#define atomic_load(object) \
__pragma(warning(push)) \
__pragma(warning(disable:28112)) \
(*(object)) \
__pragma(warning(pop))
但是分析人员坚持我应该一直使用
Interlocked*
函数,这使我相信必须有更好的方法。如果是这样,那是什么? 最佳答案
我认为忽略分析器在这里是可以接受的,因为the documentation说简单读取寄存器宽度变量是安全的(32位系统上为32位,64位系统上为64位)。 The warning documentation itself基本上说过谨慎,即使访问可能是安全的。
就是说,如果要关闭它,则始终可以使用幂等的Interlocked
操作来获得所需的行为。例如,您可以定义:
#define atomic_load(object) InterlockedOr((object), 0)
由于按位或使用
0
永远不会更改该值,并且它始终返回原始值,因此最终结果是在原子地不写入任何内容的情况下读取原始值。如果您使用
atomic_load_explicit
模拟memory_order_relaxed
,则可以通过使用 InterlockedOrNoFence
to avoid memory barriers来获得更好的性能,但是要模拟默认(顺序一致)的atomic_load
,则需要使用InterlockedOr
。InterlockedOr
几乎是任意选择的(从理论上讲,它在硬件上可能比带有进位(如加法或减法)的操作稍快一些),但是InterlockedXor
为0的行为应与其他几种操作相同,只要它们是他们的身份值(value)。您也可以类似的方式使用
InterlockedCompareExchange
;需要测试以确定哪个更快:#define atomic_load(object) InterlockedCompareExchange((object), 0, 0)
再次,如果该值已经为0,则将其设置为零,但是您真正使用的唯一目的是获取返回值,即无操作交换之前的原始值。
关于c - MSVC中C中的原子负载,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42660091/