C/C++ 内存模型是否允许相同字节的不同粒度的原子?
Does the C/C++ memory model allow atomics at different granularities for the same bytes?
假设我有以下类型:
struct T {
int32 high;
int32 low;
};
是否定义了对所有 x
、&x->high
和 &x->low
执行原子访问(例如使用 atomic_load
、atomic_fetch_add
)的行为(假设 U* x
)?
我的理解是 C/C++ 内存模型是使用多个单独位置的历史定义的(以适应弱内存架构)。如果访问可以跨位置,这是否意味着跨位置同步?如果是这种情况,那么我假设这意味着历史本质上是按字节计算的,访问 int
就像在底层 4(或 8)字节之间进行同步。
edit: 修改示例以避免合并,因为问题的主要部分是关于并发模型的。
edit:修改为使用 stdatomic.h
中的标准原子
无论是否使用 __atomic_load
加载非活动联合成员都会产生不确定的值。
对于 C11/C18(我不能谈论 C++)标准 atomic_xxx()
<stdatomic.h>
的函数仅定义为采用 _Atomic
限定参数。因此,要对 struct T
的字段进行 atomic_xxx()
操作,您需要:
struct T {
_Atomic int32 high;
_Atomic int32 low;
} ;
struct T foo, bar ;
然后你就可以做到(例如)atomic_fetch_add(&foo->high, 42)
。但是 bar = atomic_load(&foo)
将是未定义的。
相反,您可以:
struct T {
int32 high;
int32 low;
} ;
_Atomic struct T foo ;
struct T bar ;
现在 bar = atomic_load(&foo)
已定义。但是对 foo
中任何单个字段的访问是未定义的——无论它是否是 _Atomic
.
按照标准,_Atomic xxxx
对象应该被认为与 "ordinary" xxxx
对象完全不同——它们可能具有不同的大小、表示和对齐方式。因此,投射一个 xxxx
to/from 一个 _Atomic xxxx
并不比投射一个 struct
to/from 另一个不同的 struct
.[=33 更明智=]
但是,对于 gcc 和 __atomic_xxx()
内置函数,您可以做任何处理器支持的事情。实际上,对于 gcc,(否则)标准 atomic_xxx()
将接受 not_Atomic
合格类型的参数,并映射到内置参数。另一方面,clang 将 not _Atomic
限定类型传递给标准函数视为错误。恕我直言,这是 gcc <stdatomic.h>
.
中的错误
假设我有以下类型:
struct T {
int32 high;
int32 low;
};
是否定义了对所有 x
、&x->high
和 &x->low
执行原子访问(例如使用 atomic_load
、atomic_fetch_add
)的行为(假设 U* x
)?
我的理解是 C/C++ 内存模型是使用多个单独位置的历史定义的(以适应弱内存架构)。如果访问可以跨位置,这是否意味着跨位置同步?如果是这种情况,那么我假设这意味着历史本质上是按字节计算的,访问 int
就像在底层 4(或 8)字节之间进行同步。
edit: 修改示例以避免合并,因为问题的主要部分是关于并发模型的。
edit:修改为使用 stdatomic.h
无论是否使用 __atomic_load
加载非活动联合成员都会产生不确定的值。
对于 C11/C18(我不能谈论 C++)标准 atomic_xxx()
<stdatomic.h>
的函数仅定义为采用 _Atomic
限定参数。因此,要对 struct T
的字段进行 atomic_xxx()
操作,您需要:
struct T {
_Atomic int32 high;
_Atomic int32 low;
} ;
struct T foo, bar ;
然后你就可以做到(例如)atomic_fetch_add(&foo->high, 42)
。但是 bar = atomic_load(&foo)
将是未定义的。
相反,您可以:
struct T {
int32 high;
int32 low;
} ;
_Atomic struct T foo ;
struct T bar ;
现在 bar = atomic_load(&foo)
已定义。但是对 foo
中任何单个字段的访问是未定义的——无论它是否是 _Atomic
.
按照标准,_Atomic xxxx
对象应该被认为与 "ordinary" xxxx
对象完全不同——它们可能具有不同的大小、表示和对齐方式。因此,投射一个 xxxx
to/from 一个 _Atomic xxxx
并不比投射一个 struct
to/from 另一个不同的 struct
.[=33 更明智=]
但是,对于 gcc 和 __atomic_xxx()
内置函数,您可以做任何处理器支持的事情。实际上,对于 gcc,(否则)标准 atomic_xxx()
将接受 not_Atomic
合格类型的参数,并映射到内置参数。另一方面,clang 将 not _Atomic
限定类型传递给标准函数视为错误。恕我直言,这是 gcc <stdatomic.h>
.