对原子结构和指针的误解

时间:2014-11-21 19:44:55

标签: c++ pointers struct atomic

我的第一个问题是:有没有办法访问atomic<struct>对象中struct的成员? 例如,我得到编译器错误:

struct std::atomic<node>’ has no member named ‘data’ a.data = 0; 

在此细分中

struct node{
  int data;
  node* next;
};

int main(){
  atomic<node> a;
  a.data = 0;
}

我可以通过创建一个像这样的临时节点来解决它:

  atomic<node> a;
  node temp;
  temp.data = 0;
  a.store(temp);

但这看起来并不优雅。

第二个问题是,如果我有一个指向原子对象的指针怎么办?反正有没有直接访问节点的成员?显然下面的代码没有编译,如何将其更改为在b的节点值中存储0?

atomic<node> b = new node;
b->data = 0;

这是我已经找到的解决方案,但是,还有更优雅的方法吗?

atomic<node> *b;
node temp;
temp.data = 0;
b->store(&temp);

最后,atomic<node*>atomic<node>*

之间有什么区别

3 个答案:

答案 0 :(得分:11)

  

这[解决方法]看起来并不优雅。

std::atomic<T>不能使任意操作成为原子:只支持加载和存储数据。这就是为什么你的&#34;解决方法&#34;实际上是处理原子对象的方法:以任何你喜欢的方式准备新的node值,然后将其原子地设置为atomic<node>变量。

  

如果我有一个指向原子对象的指针怎么办?反正是否直接访问节点的成员?

通过指针访问节点的内容也不是原子的:因为std::atomic<T>只能保证加载和存储它的值是原子的,所以它不允许你访问T&# 39;成员没有明确的副本。这是一件好事,因为它可以防止代码读者误以为对T内部的访问在某种程度上是原子的。

  

atomic<node*>atomic<node>*

之间的区别是什么?

在第一种情况下,原子对象存储一个指针,该指针可以原子方式访问(即,您可以原子地将此指针重新指向新节点)。在第二种情况下,原子对象存储可以原子方式访问的值,这意味着您可以原子地读取和写入整个node

答案 1 :(得分:2)

当你这样做时

atomic<node> a;
node temp; // use a.load() to copy all the fields of a to temp
temp.data = 0;
a.store(temp);

您失去了下一个字段的值。我会做出建议的改变。如果node是简单类型,比如 std :: atomic_int ,我认为使用“ = ”运算符是可能的。否则不是。我不认为你的案子还有另一种解决方法。

  

最后,原子&lt;之间有什么区别?节点*&gt;和原子   &LT;节点&gt; *?

如果你使用原子&lt;节点*&gt;在节点对象的地址上完成的操作将是原子操作,而在另一种情况下,您需要为原子对象分配内存,并在实际节点对象上完成操作将是原子的。

答案 2 :(得分:1)

请注意您的解决方案&#34;包括除.data以外的所有成员的非原子读 - 修改 - 写。

atomic<node> a;

node temp = a.load();
temp.data = 0;
a.store(temp); // steps on any changes to other member that happened after our load

如果你想要一个结构,你可以在其中原子地更新所有成员或单独原子地修改其中一个(在整个结构上没有compare_exchange_weak),你可以使用{{3 }}。这可能对例如双链表中的两个指针,或指针+计数器。当前的编译器甚至不会读取原子结构的一个成员,而不会像使用CMPXCHG16B加载整个结构那样慢,然后只看一个成员。 (即使使用memory_order_relaxed,gcc6.2就属于这种情况。)

只有当您使用C ++编译器保证编写一个联合成员然后读取另一个联合成员时,这种联合黑客才有效,就像它在C99中一样。

这适用于最大尺寸的结构,硬件可以cmpxchg,即x86-64上的16B(如果你在gcc中启用-mcx16),使用第一代K8 CPU没有的CMPXCHG16B支持,所以它不是技术上的基线x86-64)。

对于较大的结构,atomic<the_whole_thing>不会无锁,并且通过另一个工会成员中的atomic<int>对其成员进行读/写将不安全。尽管如此,阅读仍然可以。

这可能会使内存排序语义变得混乱,因为即使是强排序的x86也可以a union of an atomic struct and a struct with two atomic members 。如果你大多只需要原子性,那就太棒了,但是在刚编写一个成员的同一个线程中读取完整对象(例如在执行cmpxchg时)需要在x86上使用MFENCE,即使是获取/释放语义。您将始终看到自己的商店,但如果其他线程存储到同一个对象,他们可以在您加载后观察您的商店。