我的问题涉及std::atomic<T*>
和这个指针指向的数据。
Object A;
std:atomic<Object*> ptr;
int bar = 2;
A.foo = 4; //foo is an int;
ptr.store(*A);
如果在线程2中,我观察到ptr
指向A
,我能保证ptr->foo
是4,bar
是2吗?
原子指针的默认内存模型(顺序一致)是否保证在原子存储之前发生的非原子(在本例中为A.foo
)上的赋值将在其他线程看到相同atomic.store
的赋值之前被其他线程看到?
如果有帮助或重要,我使用x64(我只关心这个平台),gcc(支持原子的版本)。
2条答案
按热度按时间kdfy810k1#
答案是肯定的,也可能是否定的
内存模型原则:
C++11原子使用by default
std::memory_order_seq_cst
内存排序,这意味着操作是顺序一致的。其语义是所有操作的排序就好像所有这些操作都是顺序执行的:
你的问题的答案是肯定的!
非原子数据的风险
然而,您应该意识到,实际上,对于非原子值,一致性保证更加有限。
假设第一执行场景:
在这里,
i
是4。因为ptr
是原子的,所以线程(2)在读取指针时安全地获得值&A
。内存顺序确保所有在ptr
之前进行的分配都被其他线程看到(“发生在”约束)。但是假设第二执行场景:
这里的结果是未定义的。它可能是4,因为内存排序保证了在
ptr
赋值之前发生的事情被其他线程看到。但是没有什么可以阻止之后的赋值也被看到。所以它可能是8。如果你有
*ptr = 8;
而不是A.foo=8;
,那么你会再次确定:i
是8。你可以通过实验来验证这一点,例如:
结论
总而言之,您的问题的答案是肯定的,但前提是同步后没有对非原子数据进行其他更改。主要风险是只有
ptr
是原子的。但这并不适用于所指向的值。需要注意的是,当你将原子指针重新分配给非原子指针时,特别是指针会带来进一步的同步风险。
示例:
y4ekin9u2#
默认情况下,C++-11原子操作具有获取/释放语义。
所以一个线程看到你的store也会看到在它之前执行的所有操作。
你可以找到更多的细节here。