C++ std::原子结构和自定义结构的问题

C++ std::原子结构和自定义结构的问题,c++,struct,atomic,stdatomic,C++,Struct,Atomic,Stdatomic,由于某些原因,似乎无法执行此操作(请参见代码)。查看文档,似乎没有理由不起作用 struct vector { float x, y, z; }; std::atomic<vector> Name = {0}; std::atomic的实例不是vector的实例。它没有x、y或z作为成员。它所拥有的(概念上,内部)是vector的一个实例。但是您不能使用操作符访问它,因为这会破坏原子性,就像std::atomic的点一样。(这也是为什么不能使用初始值设定项列表。) 要访问向

由于某些原因,似乎无法执行此操作(请参见代码)。查看文档,似乎没有理由不起作用

struct vector {
    float x, y, z;
};
std::atomic<vector> Name = {0};

std::atomic
的实例不是
vector
的实例。它没有
x
y
z
作为成员。它所拥有的(概念上,内部)是
vector
的一个实例。但是您不能使用
操作符访问它,因为这会破坏原子性,就像
std::atomic
的点一样。(这也是为什么不能使用初始值设定项列表。)

要访问
向量
内容,请使用
load()
store()


这里有
std::atomic
的文档

std::atomic
上没有成员x、y和z

std::atomic
是一种可以原子地替换整个X的类型,而不是它的单个部分


您可能需要的是互斥,因为对于像
name\u snapshot
这样的结构,std::atomic在任何情况下都将使用互斥。因为不太可能有原子指令来处理整个结构的原子加载/存储。

它是
Name.\u My\u val.x,Name.\u My\u val.y,Name.\u My\u val.z
不是
Name.x,Name.y,Name.z


为什么没有人告诉我这是我无法理解的,但不管怎样。

在某些编译器上,例如针对x86-64的gcc或clang,
atomic
对最多16个字节的T是无锁的。即使对于
.load()
.store()
,它也必须使用
锁cmpxchg16b
,因此效率不高。(出于这个原因,gcc7和更高版本为
。is_lock_free()返回false)
,并且不内联
锁cmpxchg16b
,而是始终调用库函数。即使当前库实现是无锁的,并且不能在不破坏与内联代码的兼容性的情况下进行更改
锁cmpxchg16b
)良好
.load()
.store
示例。也许一个好主意是指出它不是一个原子RMW;你必须使用CAS循环来实现这一点。它只是一个原子加载和一个后来的无条件原子存储,可以对来自其他线程的更新进行跟踪编译得很好(),其他让
atomic
将参数从its转发到
T()
构造函数的方法也是如此,比如
std::atomic Name2{{{{1.0,1.0,2.0}Name.store({0,0,0})
或者我需要创建一个实际变量吗?@vidsac:是的,你可以使用
vector({0,0,0})
创建一个匿名临时变量,这样你就可以执行
Name.store(vector({0,0,0}),std::memory\u order\u。看到了吗?这是否会锁定结构,使其他线程无法访问它?不,不是。您在这里所做的是处理内部实现细节。它将无法按您的意愿运行。您正在绕过内存限制。这些操作将不是原子操作。是希望结构具有单独的原子成员,还是希望整个结构充当单个原子对象?无论如何,这只在MSVC上编译,其中12字节的结构不是无锁的,因此这将破坏其他原子操作的原子性。它甚至不在其他编译器上编译。@RichardHodges:它绕过了锁。有序性和原子性是分开的;您可以拥有原子性而无需任何围栏(例如,使用
内存\u顺序\u松弛的
)。从技术上讲,
Name.\u My_val.x
的存储在x86上将是原子的,因为它将自然对齐。但是用多个成员做任何事情,或者读然后写,也绝对不是原子的。正如您所指出的,即使是普通存储也会通过忽略锁来打破其他RMW操作的原子性。如果您真的希望以原子方式访问整个结构,并且您的工作负载主要由读取控制,请查看用户空间RCU或seqlocks。
Name.x = 4.f;
Name.y = 2.f * Name.x;
Name.z = 0.1f;
//atomically load a snapshot of Name
auto name_snapshot = Name.load(); //name_snapshot is a vector instance
name_snapshot.x = 4.f;
name_snapshot.y = 2.f * name_snapshot.x;
name_snapshot.z = 0.1f;
//now atomically store it:
Name.store(name_snapshot);