我读了一章,我不喜欢它.我还不清楚每个内存顺序之间的差异.这是我目前的推测,我在阅读更简单的http://en.cppreference.com/w/cpp/atomic/memory_order后理解这一点.
以下是错误的,所以不要试图从中学习
a在另一个线程上放宽了存储.我b用seq_cst 存储.第三个线程读取a 放松将看到变化以及b任何其他原子变量? ).如果我错了,我想我理解但是纠正我.我找不到任何用易于阅读的英语解释它的东西.
C++11 引入了一种新的内存模型,让“运行”C++11 代码的抽象机器有关于多线程的概念。它还引入了一组内存顺序,内存加载/存储操作遵循这些顺序。
C++20 的维基百科页面说它有
修改后的内存模型。
它给出的参考资料说 C++11 的内存模型有许多缺陷,C++20 将对其进行修改。
有人可以举例说明 C++11 的内存模型带来的问题,以及 C++20 中的问题如何解决吗?
相关问题: C++11的内存模型介绍
在C ++草案标准中多次使用了“在……之前发生”一词。
例如:终止 [basic.start.term] / 5
如果在调用std?::?atexit之前强烈完成了具有静态存储持续时间的对象的初始化(请参见[support.start.term]),则对该函数的调用将传递给std?::?atexit。在调用对象的析构函数之前进行排序。如果对std?::?atexit的调用很强地发生在具有静态存储持续时间的对象的初始化完成之前,则在传递给std?::?atexit的函数的调用之前对对象的析构函数的调用进行排序。 。如果对std?::?atexit的调用在另一次对std?::?atexit的调用之前强烈发生,则传递给第二个std?::?atexit调用的函数的调用将在传递给函数的函数的调用之前按顺序进行。第一个std?::?atexit调用。
并在 数据竞赛 [intro.races] / 12中定义
评估A发生在评估D之前,如果发生以下情况之一
(12.1)A在D之前排序,或
(12.2)A与D同步,并且A和D都是顺序一致的原子操作([atomics.order]),或者
(12.3)对B和C进行求值,使得A在B之前排序,B恰好在C之前发生,而C在D之前排序,或者
(12.4)有一个评估B,使得A强烈发生在B之前,而B强烈发生在D之前。
[注意:非正式地,如果A强烈地发生在B之前,那么在所有情况下A似乎都在B之前被评估。强烈发生在排除消耗操作之前。—尾注]
为什么引入“强烈发生”?直觉上,它与“之前发生的事情”有什么区别和关系?
注释中的“在所有情况下A似乎都在B之前被评估”是什么意思?
(注意:此问题的动机是Peter Cordes在此答案下的评论。)
标准报价附加草案(感谢Peter Cordes)
满足以下约束的所有memory_order?::?seq_cst操作(包括栅栏)上只有一个总顺序S。首先,如果A和B是memory_order?::?seq_cst运算,并且A强烈地发生在B之前,那么A在S中先于B。其次,对于对象M上的每对原子操作A和B,A的相干性在B之前,S必须满足以下四个条件:
(4.1)如果A和B都是memory_order?::?seq_cst操作,则A在S中先于B;和
(4.2)如果A是一个memory_order?::?seq_cst操作,而B发生在memory_order?::?seq_cst栅栏Y之前,则A在S中位于Y之前;和
(4.3)如果memory_order?::?seq_cst栅栏X发生在A之前,而B是memory_order?::?seq_cst操作,则X在S之前位于B之前;和
(4.4)如果memory_order?::?seq_cst防护栏X发生在A之前,而B发生在memory_order?::?seq_cst防护栏Y之前,则X在S中位于Y之前。
c++ multithreading memory-model language-lawyer happens-before
我试图了解std::atomic_thread_fence(std::memory_order_seq_cst);栅栏的用途,以及它们与栅栏有何不同acq_rel。
到目前为止,我的理解是,唯一的区别是 seq-cst 栅栏影响 seq-cst 操作的全局顺序 ( [atomics.order]/4)。并且只有在实际执行 seq-cst 加载时才能观察到所述顺序。
所以我想,如果我没有 seq-cst 负载,那么我可以用 acq-rel 栅栏替换所有 seq-cst 栅栏,而不改变行为。那是对的吗?
如果这是正确的,为什么我会看到这样的代码“使用栅栏实现 Dekker 算法”,它使用 seq-cst 栅栏,同时保持所有原子读/写宽松?这是该博客文章中的代码:
std::atomic<bool> flag0(false),flag1(false);
std::atomic<int> turn(0);
void p0()
{
flag0.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag1.load(std::memory_order_relaxed))
{
if (turn.load(std::memory_order_relaxed) != 0)
{
flag0.store(false,std::memory_order_relaxed);
while (turn.load(std::memory_order_relaxed) != 0)
{
}
flag0.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
}
std::atomic_thread_fence(std::memory_order_acquire);
// critical section
turn.store(1,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
flag0.store(false,std::memory_order_relaxed);
}
void p1()
{
flag1.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag0.load(std::memory_order_relaxed))
{
if (turn.load(std::memory_order_relaxed) != 1)
{
flag1.store(false,std::memory_order_relaxed);
while …Run Code Online (Sandbox Code Playgroud) 我读过这个问答:与“(简单)发生在之前”相比,“强烈发生在之前”的意义是什么?
作者给出了一个有趣的评估的概述,该评估在 C++20 之前是不可能的,但显然从 C++20 开始是可能的:
.-- T3 y.store(3, seq_cst); --. (2)
| | | strongly
| | sequenced before | happens
| V | before
| T3 a = x.load(seq_cst); // a = 0 --. <-' (3)
| : coherence-
| : ordered
| : before
| T1 x.store(1, seq_cst); <-' --. --. (4)
| | |st |
| | sequenced before |h |
| V |b |
| . T1 y.store(1, release); <-' | (x)
| | …Run Code Online (Sandbox Code Playgroud)