C++20 内存模型中释放序列定义的更改有何影响?

2024-04-20

考虑这个程序:

-- Initially --
std::atomic<int> x{0};
int y{0};
    
-- Thread 1 --
y = 1;                                      // A
x.store(1, std::memory_order_release);      // B
x.store(3, std::memory_order_relaxed);      // C

-- Thread 2 --
if (x.load(std::memory_order_acquire) == 3) // D
    print(y);                               // E

在C++11内存模型下,如果程序打印任何内容,那么它会打印 1 https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0982r1.html.

在 C++20 内存模型中,发布顺序已更改 https://en.cppreference.com/w/cpp/atomic/memory_order#Release_sequence排除由同一线程执行的写入。这对这个程序有何影响?现在可以进行数据竞争并打印吗0 or 1?

Notes

这段代码出现在P0982R1:削弱释放序列 https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0982r1.html我相信这篇论文导致了 C++20 中发布序列定义的更改。在该特定示例中,有第三个线程进行存储x这以一种违反直觉的方式破坏了释放顺序。这激发了削弱发布顺序定义的需要。

通过阅读该论文,我的理解是,随着C++20的变化,C将不再构成以B为首的发布序列的一部分,因为C不是读-修改-写操作。因此 C 不与 D 同步。因此不存在发生在之前A和E之间的关系。

由于 B 和 C 存储到相同的原子变量并且所有线程必须就该变量的修改顺序达成一致 https://stackoverflow.com/a/27333661,C++20 内存模型是否允许我们推断 A 是否发生在 E 之前?


您的理解是正确的;该程序存在数据竞争。 3 的存储不构成任何发布序列的一部分,因此 D 不与任何发布存储同步。因此,无法在两个不同线程的任何两个操作之间建立任何发生前关系,特别是 A 和 E 之间没有发生前关系。

我认为从 3 的负载中你可以推断出的唯一一件事是 D 绝对不会在 C 之前发生;如果是这样,那么 D 将有义务加载一个在修改顺序中严格位于较早位置的值x[读写一致性,intro.races p17]。这尤其意味着 E 不会发生在 A 之前。

如果您要从以下位置加载,则修改顺序将发挥作用x再次在线程 2 中 D 之后的某个位置。然后您将保证再次加载值 3。这是从读读连贯性得出的结论 [intro.races p16]。您的第二个加载不允许观察修改顺序中 3 之前的任何内容,因此它无法加载值 0 或 1。即使两个线程中的所有加载和存储都被放松,这也适用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++20 内存模型中释放序列定义的更改有何影响? 的相关文章

随机推荐