我想尝试使用如下方式自动重置 256 位:
#include <x86intrin.h>
#include <iostream>
#include <array>
#include <atomic>
int main(){
std::array<std::atomic<__m256i>, 10> updateArray;
__m256i allZeros = _mm256_setzero_si256();
updateArray[0].fetch_and(allZeros);
}
但我收到有关该元素没有的编译器错误fetch_and()
。这是否不可能,因为 256 位类型太大而无法保证原子性?
我还有其他方法可以实现这个吗?我正在使用海湾合作委员会。
如果不是,我可以自动重置的最大类型是什么 - 64 位?
编辑:任何 AVX 指令都可以原子地执行 fetch-AND 吗?
因此,有几个不同的问题需要解决:
- 处理器能做什么?
- 原子性是什么意思?
- 你能让编译器生成处理器能做的事情的代码吗?
- C++11/14 标准支持吗?
对于#1 和#2:
在 x86 中,有执行 8、16、32、64、128、256 和 512 位操作的指令。一个处理器将[至少如果数据与其自身的大小对齐]以原子方式执行该操作。然而,为了使操作成为“真正的原子”,它还需要防止数据更新中的竞争条件[换句话说,防止其他处理器读取、修改和写回同一位置]。除了少量的“隐含锁定”指令之外,这是通过向特定指令添加“锁定前缀”来完成的 - 这将对系统中的其他处理器执行正确类型的缓存对话[技术术语],以确保只有该处理器才能更新该数据。
我们不能使用带有 LOCK 前缀的 VEX 指令(来自 Intel 手册)
任何在 VEX 之前带有 LOCK 前缀的 VEX 编码指令都将 #UD
使用 AVX 指令需要 VEX 前缀,#UD 表示“未定义指令”——换句话说,如果我们尝试执行该代码,就会导致处理器异常。
因此,100% 确定处理器不能一次对 256 位执行原子操作。这个答案讨论了 SSE 指令原子性:SSE指令:哪些CPU可以进行原子16B内存操作?
如果指令无效,#3 就毫无意义。
#4 - 好吧,标准支持std::atomic<uintmax_t>
, 而如果uintmax_t
恰好是 128 或 256 位,那么你当然可以这样做。我不知道有任何处理器支持 128 或更高位uintmax_t
,但语言并不能阻止它。
如果“原子”的要求不如“需要 100% 确保没有其他处理器同时更新它”那么强烈,那么使用常规 SSE、AVX 或 AVX512 指令就足够了 - 但会出现竞争条件如果您有两个处理器(核心)同时对同一位内存执行读/修改/写操作。
x86 上最大的原子操作是 CMPXCHG16B,如果其他两个寄存器中的值与内存中的值匹配,它将用内存中的内容交换两个 64 位整数寄存器。因此,您可以想出一些方法来读取一个 128 位值,并输出一些位,然后如果没有其他内容首先进入其中,则自动将新值存储回来 - 如果发生这种情况,您必须重复该操作,当然,它也不是单个原子与操作。
当然,在 Intel 和 AMD 之外的其他平台上,行为可能会有所不同。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)