Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对原子结构和指针的误解_C++_Pointers_Struct_Atomic - Fatal编程技术网

C++ 对原子结构和指针的误解

C++ 对原子结构和指针的误解,c++,pointers,struct,atomic,C++,Pointers,Struct,Atomic,我的第一个问题是:有没有办法访问原子对象中的struct成员? 例如,我得到编译器错误: struct std::atomic<node>’ has no member named ‘data’ a.data = 0; struct std::atomic'没有名为'data'的成员a.data=0; 在这一部分 struct node{ int data; node* next; }; int main(){ atomic<node> a; a.

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

struct std::atomic<node>’ has no member named ‘data’ a.data = 0; 
struct std::atomic'没有名为'data'的成员a.data=0;
在这一部分

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

int main(){
  atomic<node> a;
  a.data = 0;
}
struct节点{
int数据;
节点*下一步;
};
int main(){
原子a;
a、 数据=0;
}
我可以通过如下方式创建临时节点来解决此问题:

  atomic<node> a;
  node temp;
  temp.data = 0;
  a.store(temp);
原子a;
节点温度;
温度数据=0;
a、 仓库(临时);
但这看起来不太优雅

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

atomic<node> b = new node;
b->data = 0;
原子b=新节点;
b->data=0;
这是我找到的一个解决方案,但再一次,有没有更优雅的方法来实现这一点

atomic<node> *b;
node temp;
temp.data = 0;
b->store(&temp);
原子*b;
节点温度;
温度数据=0;
b->store(&temp);
最后,原子的和原子的有什么区别

这个[解决办法]似乎不太优雅

std::atomic
无法使任意操作原子化:仅支持加载和存储数据。这就是为什么您的“变通方法”实际上是处理原子对象的方法:您可以以任何喜欢的方式准备新的
节点
值,然后将其原子地设置为
原子
变量

如果我有一个指向原子对象的指针呢?是否仍然可以直接访问节点的成员

通过指针访问节点的内容也不会是原子的:因为
std::atomic
只能保证加载和存储其原子值,所以它不允许您在不创建显式副本的情况下访问
T
的成员。这是一件好事,因为它可以防止代码读者误以为访问
T
的内部是原子的

原子的
原子的*

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

atomic<node> a;
node temp; // use a.load() to copy all the fields of a to temp
temp.data = 0;
a.store(temp);
原子a;
节点温度;//使用.load()将所有字段复制到临时文件
温度数据=0;
a、 仓库(临时);
您失去了下一个字段的值。我会做出建议的改变。如果节点是一个简单类型,比如std::atomic_int,我认为使用“=”操作符是可能的。否则就不行了。我认为你的案子没有其他解决办法了

最后,原子的和原子的区别是什么 *

如果您使用原子上执行的操作,节点对象的地址将是原子的,而在另一种情况下,您需要为原子对象分配内存,在上执行的操作,实际节点对象将是原子的。

请注意您的“解决方案”包括除
.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
原子a;
节点温度=a.load();
温度数据=0;
a、 存储(临时);//加载后对其他成员所做的任何更改的步骤


如果您想要一个可以同时原子地更新所有成员或单独原子地修改其中一个成员的结构(在整个结构上没有
compare\u exchange\u weak
),可以使用。这可能对双链接列表中的两个指针或指针+计数器都有用。当前的编译器甚至不善于读取原子结构的一个成员,而不做一些缓慢的事情,比如使用CMPXCHG16B加载整个结构,然后只查看一个成员。(gcc6.2上就是这种情况,即使
内存\u顺序\u松弛

<>这个联合黑客只有在使用C++编译器时才能够保证编写一个联合成员,然后读取另一个成员是可以的,就像在C99 ./P>中一样。 这适用于硬件可以达到cmpxchg最大大小的结构,即x86-64上的16B(如果在gcc中启用
-mcx16
,则使用第一代K8 CPU不支持的CMPXCHG16B,因此它不是x86-64的技术基线)

对于较大的结构,
atomic
将不会无锁,并且通过另一个联合成员中的
atomic
读取/写入它的成员将不安全。尽管如此,读书还是可以的


这可能会弄乱内存排序语义,因为即使是强排序的x86也可以。如果您主要只需要原子性,这很好,但是在刚刚编写一个成员的同一线程中读取完整对象(例如,在执行cmpxchg时)需要x86上的MFENCE,即使对于获取/发布语义也是如此。您将始终看到自己的存储,但如果其他线程正在存储到同一对象,它们可以观察到您的存储在加载后发生。

因此,如果我想以原子方式更改成员,我应该将成员设置为原子,而不是结构?@MattPennington!如果您希望对
节点
中的数据的访问是原子的,那么您的节点将如下所示:
结构节点{atomic data;}只要你同意在任何情况下使用你的结构的每个人都使用原子结构。如果您只担心一些特定上下文中的线程安全,那么最好只使用一个单独的互斥锁。现在这就更有意义了。谢谢。不,只有一组有限的原子操作(加载、存储、交换等)
atomic
强制对它所持有的指针(不是指针指向的东西,只是指针)进行原子更新<代码>原子*
是一个