我正在编写一些无锁代码,并且想出了一个有趣的模式,但我不确定它在宽松的内存排序下是否会按预期运行。
解释它的最简单方法是使用示例:
std::atomic<int> a, b, c;
auto a_local = a.load(std::memory_order_relaxed);
auto b_local = b.load(std::memory_order_relaxed);
if (a_local < b_local) {
auto c_local = c.fetch_add(1, std::memory_order_relaxed);
}
请注意,所有操作都使用std::memory_order_relaxed
.
显然,在执行此操作的线程上,必须在评估条件之前完成加载a
和b
必须完成。if
c
类似地,必须在评估条件后执行读取-修改-写入 (RMW) 操作(因为它以该条件为条件)。
我想知道的是,这段代码是否保证 的值c_local
至少与a_local
and的值一样最新b_local
?如果是这样,考虑到宽松的内存顺序,这怎么可能?控制依赖与 RWM 操作一起充当某种获取栅栏吗?(请注意,任何地方都没有相应的版本。)
如果上述情况成立,我相信这个例子也应该有效(假设没有溢出)——我是对的吗?
std::atomic<int> a(0), b(0);
// Thread 1
while (true) {
auto a_local = a.fetch_add(1, std::memory_order_relaxed);
if (a_local >= 0) { // Always true at runtime
b.fetch_add(1, std::memory_order_relaxed);
}
}
// Thread 2
auto b_local = b.load(std::memory_order_relaxed);
if (b_local < 777) {
// Note that fetch_add returns the pre-incrementation value
auto a_local = a.fetch_add(1, std::memory_order_relaxed);
assert(b_local <= a_local); // Is this guaranteed?
}
在线程 1 上,有一个控制依赖项,我怀疑它保证在a
递增之前总是b
递增(但它们每个都保持并列递增)。在线程 2 上,还有另一个控制依赖项,我怀疑它保证b
加载到b_local
之前a
会增加。我还认为,从返回的值fetch_add
将至少与 中的任何观察值一样新b_local
,assert
因此应该成立。但我不确定,因为这与通常的内存排序示例大相径庭,而且我对 C++11 内存模型的理解并不完美(我无法确定地推理这些内存排序效果)。任何见解将不胜感激!
更新:正如 bames53 在评论中有用地指出的那样,给定一个足够智能的编译器,有可能if
在适当的情况下完全优化an比fetch_add
返回值更新(assert
在我的第二个示例中可能会触发)。但是,如果插入(not ) 而不是if
an怎么办?不管做了什么优化,编译器肯定不能忽略这一点,但它是否确保代码的行为符合预期?在这种情况下,CPU 是否允许进行任何重新排序?atomic_signal_fence
atomic_thread_fence
然后第二个示例变为:
std::atomic<int> a(0), b(0);
// Thread 1
while (true) {
auto a_local = a.fetch_add(1, std::memory_order_relaxed);
std::atomic_signal_fence(std::memory_order_acq_rel);
b.fetch_add(1, std::memory_order_relaxed);
}
// Thread 2
auto b_local = b.load(std::memory_order_relaxed);
std::atomic_signal_fence(std::memory_order_acq_rel);
// Note that fetch_add returns the pre-incrementation value
auto a_local = a.fetch_add(1, std::memory_order_relaxed);
assert(b_local <= a_local); // Is this guaranteed?
另一个更新:在阅读了到目前为止的所有回复并自己梳理了标准之后,我认为仅使用标准不能证明代码是正确的。那么,任何人都可以提出一个符合标准并触发断言的理论系统的反例吗?