[英]C++11 Atomic memory order with non-atomic variables
I am unsure about how the memory ordering guarantees of atomic variables in c++11 affect operations to other memory. 我不确定c ++ 11中的原子变量的内存排序保证如何影响对其他内存的操作。
Let's say I have one thread which periodically calls the write function to update a value, and another thread which calls read to get the current value. 假设我有一个线程周期性地调用write函数来更新一个值,另一个线程调用read来获取当前值。 Is it guaranteed that the effects of
d = value;
是否保证
d = value;
的影响d = value;
will not be seen before effects of a = version;
在
a = version;
效果之前不会被看到a = version;
, and will be seen before the effects of b = version;
,并且会在
b = version;
的影响之前看到b = version;
? ?
atomic<int> a {0};
atomic<int> b {0};
double d;
void write(int version, double value) {
a = version;
d = value;
b = version;
}
double read() {
int x,y;
double ret;
do {
x = b;
ret = d;
y = a;
} while (x != y);
return ret;
}
Your object d
is written and read by two threads and it's not atomic. 您的对象
d
由两个线程写入和读取,并且它不是原子的。 This is unsafe, as suggested in the C++ standard on multithreading: 这是不安全的,如多线程的C ++标准所示:
1.10/4 Two expression evaluations conflict if one of them modifies a memory location and the other one accesses or modifies the same memory location.
1.10 / 4如果其中一个修改了内存位置而另一个访问或修改了相同的内存位置,则两个表达式评估会发生冲突。
1.10/21 The execution of a program contains a data race if it contains two conflicting actions in different threads,at least one of which is not atomic, and neither happens before the other.
1.10 / 21程序的执行包含数据竞争,如果它在不同的线程中包含两个冲突的动作,其中至少有一个不是原子的,并且都不会发生在另一个之前。 Any such data race results in undefined behavior.
任何此类数据争用都会导致未定义的行为。
Important edit: 重要编辑:
In your non-atomic case, you have no guarantees about the ordering between the reading and the writing. 在非原子的情况下,你无法保证阅读和写作之间的顺序。 You don't even have guarantee that the reader will read a value that was written by the writer (this short article explains the risk for non-atomic variables).
您甚至不能保证读者会读取作者写的值(这篇简短的文章解释了非原子变量的风险 )。
Nevertheless , your reader's loop finishes based on a test of the surrounding atomic variables, for which there are strong guarantees. 然而 ,读者的循环基于对周围原子变量的测试而完成,对此有很强的保证。 Assuming that
version
never repeats between writer different calls, and given the reverse order in which you aquire their value: 假设
version
从不在编写者不同的调用之间重复,并且给出了获取其值的相反顺序:
d
read compared to the d
write can't be unfortunate if the two atomics are equal. d
写相比, d
读的顺序不可能是不幸的。 This means that in case of an adverse race condition on your non-atomic, thanks to the loop, you'll end-up reading the last value
. 这意味着如果你的非原子的不利竞争条件,由于循环,你将最终读取最后一个
value
。
The rule is that, given a write
thread that executes once, and nothing else that modifies a
, b
or d
, 规则是,给定一个执行一次的
write
线程,没有其他任何修改a
, b
或d
,
a
and b
from a different thread at any time, and a
和b
b
and see version
stored in it, then b
并查看存储在其中的version
,那么
d
; d
; and value
. value
。 Note that whether the second part is true depends on the memory ordering; 注意第二部分是否为真取决于内存排序; it is true with the default one (
memory_order_seq_cst
). 它与默认值(
memory_order_seq_cst
)一样。
Is it guaranteed that the effects of
d = value;
是否保证
d = value;
的影响d = value;
will not be seen before effects ofa = version;
在
a = version;
效果之前不会被看到a = version;
, and will be seen before the effects ofb = version;
,并且会在
b = version;
的影响之前看到b = version;
??
Yes, it is. 是的。 This is because sequensial consistency barrier is implied when read or write
atomic<>
variable. 这是因为在读取或写入
atomic<>
变量时隐含了顺序一致性障碍 。
Instead of storing version
tag into two atomic variables before value's modification and after it, you can increment single atomic variable before and after modification: 不是在修改值之前和之后将
version
标记存储到两个原子变量中,而是可以在修改之前和之后增加单个原子变量:
atomic<int> a = {0};
double d;
void write(double value)
{
a = a + 1; // 'a' become odd
d = value; //or other modification of protected value(s)
a = a + 1; // 'a' become even, but not equal to the one before modification
}
double read(void)
{
int x;
double ret;
do
{
x = a;
ret = value; // or other action with protected value(s)
} while((x & 2) || (x != a));
return ret;
}
This is known as seqlock in the Linux kernel: http://en.wikipedia.org/wiki/Seqlock 这在Linux内核中称为seqlock : http : //en.wikipedia.org/wiki/Seqlock
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.