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/

10-13 05:13