我知道int128_tC和C++中存在一个类型.
如果我有两个线程,一个从包含这个128位整数的存储器位置读取,另一个正在写入它.
是否有可能将此值写为两个64位整数写入,还是一个128位整数写入?
根据我的阅读,IA-32架构有10个32位和6个16位寄存器.
32位寄存器如下:
16位寄存器如下:
但是,我找不到有关当前指令寄存器(CIR)或存储器缓冲寄存器(MBR)/存储器数据寄存器(MBR)的任何信息.这些寄存器是否被称为其他东西?这些寄存器是32位吗?
我假设它们是32位的,并且在这种架构下最常用的指令长度不超过4个字节.从观察来看,许多指令似乎都在4个字节以下,例如:
对于更长的指令,CPU将使用前缀代码和其他可选代码.较长的指令需要多个周期才能完成,这取决于指令长度.
我是否正确,因为有问题的寄存器长度为32位?IA-32架构中是否还有其他寄存器,我也应该注意这些寄存器?
我想知道,64 位操作系统和基于 x64 的处理器是否意味着字大小(即处理器和物理内存之间的内存传输大小)是 64 位?如果操作系统是 32 位且处理器为 x64 呢?那么基于 x86 的处理器呢?这两个规范(XX 位操作系统和基于 xXX 的处理器)与硬件中的实际字长有什么关系?
16 字节atomic<>变量是否在 16 字节边界上自动对齐,从而允许编译器/运行时库有效地使用 x86CMPXCHG16B指令?或者我们应该根据风格总是手动指定alignas(16)所有这些变量?
这是一个后续问题
有很多文章和博客提到 Java 和 JVM 指令重新排序,这可能会导致用户操作中出现反直觉的结果。
当我要求演示 Java 指令重新排序导致意外结果时,有几条评论说,更普遍的关注领域是内存重新排序,并且很难在 x86 CPU 上进行演示。
指令重新排序只是内存重新排序、编译器优化和内存模型等更大问题的一部分吗?这些问题真的是 Java 编译器和 JVM 特有的吗?它们是否特定于某些 CPU 类型?
java cpu-architecture memory-barriers instruction-reordering
引用gnu:
实际上,您可以假设 int 是原子的。您还可以假设指针类型是原子的;非常方便。这两个假设在 GNU C 库支持的所有机器上以及我们所知的所有 POSIX 系统上都是成立的。
这怎么可能?我见过的与锁相关的所有示例都是用int计数器制作的,例如https://www.delftstack.com/howto/c/mutex-in-c/。
我在一些生产代码中看到过如下所示的 C++ 代码。假设 x 与 uint64 对齐并且代码在 X86 系统上运行。我的理解是,在 x86 系统上读取/写入对齐的 uint64 值是原子的。那么这里额外的互斥体的目的是什么?
当调用 GetX() 时持有互斥锁时,其他一些线程可以在 GetX() 之前/之后获取互斥锁并更改 X。所以我不认为额外的互斥体会让代码更安全。
uint64 GetX()
{
Mutex l(&mutex); (1)
return x;
}
Run Code Online (Sandbox Code Playgroud) 我们假设有一个 32 位 CPU 和 2 字节short。我知道 4 字节int需要在 4 的倍数地址处对齐,以避免额外读取。
问题:
0x1读取。0x0那么,为什么 Shorts 需要以 2 的倍数地址对齐呢?0x2,为什么它会被认为是对齐和高效的,因为CPU只能从0x0读取并丢弃前两个字节?有一个问题与此非常相似,但是,答案仅告诉我们short结构体和独立变量中的对齐要求是相同的。还有一条获得 2 票赞成的评论说:
在许多机器上,当数量是 N 字节对齐时,访问 N 字节数量(至少是 {1, 2, 4, 8, 16} 中的 N)的效率最高。生活就是这样;习惯它,因为我怀疑芯片制造商会仅仅因为你认为它不应该是这样而改变它。
但为什么?
目前正在使用 GCC 查看 C/C++ 中的原子操作,发现内存中自然对齐的全局变量具有原子读取和写入。
然而,我试图按位与一个全局变量,并注意到它归结为一个读取-修改-写入序列,如果有多个线程对该字节值进行操作,那么这会很麻烦。
经过一番研究,我选择了这两个例子:
C 示例- GCC 扩展__sync_fetch_and_and
#include <stdio.h>
#include <stdint.h>
uint8_t byteC = 0xFF;
int main() {
__sync_fetch_and_and(&byteC, 0xF0);
printf("Value of byteC: 0x%X\n", byteC);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
C++ 示例- 使用原子的 C++11fetch_and
#include <iostream>
#include <atomic>
std::atomic<uint8_t> byteCpp(0xFF);
int main() {
byteCpp.fetch_and(0xF0);
std::cout << "Value of byteCpp: 0x" << std::hex << static_cast<int>(byteCpp.load()) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
其他示例如下,但它们似乎不太直观且计算成本更高。
用一个pthread_mutex_lock
uint8_t byte = 0xFF;
pthread_mutex_t byte_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&byte_mutex);
byte …Run Code Online (Sandbox Code Playgroud) 你好论坛 - 我有一些关于SIMD内在的类似/相关问题我在网上搜索了包括stackoverflow但没有找到好的答案所以请求你的帮助.
基本上我试图理解64位CPU如何在一次读取中获取所有128位,以及这种操作的要求是什么.
我编写了一些多线程但无锁的代码,这些代码在较早的支持 C++11 的 GCC(7 或更早版本)上编译并显然执行得很好。原子场是ints 等等。据我所知,我使用普通的 C/C++ 操作a=1;在原子性或事件排序不是问题的地方对它们(等)进行操作。
后来我不得不做一些双宽 CAS 操作,并像常见的那样制作了一个带有指针和计数器的小结构。我尝试执行相同的普通 C/C++ 操作,但出现了变量没有此类成员的错误。(这是您对大多数普通模板的期望,但我半期望atomic以不同的方式工作,部分原因是支持正常的往返分配,据我所知,对于ints。)。
所以两部分问题:
我们是否应该在所有情况下都使用原子方法,甚至(比如)由一个没有竞争条件的线程完成的初始化?1a) 所以一旦声明为 atomic 就无法非原子地访问?1b)我们还必须使用atomic<>方法的冗长冗长来做到这一点?
否则,如果至少对于整数类型,我们可以使用普通的 C/C++ 操作。但在这种情况下,这些操作是否与load()/相同,store()或者它们只是正常的分配?
还有一个半元问题:是否有任何关于为什么atomic<>变量不支持普通 C/C++ 操作的见解?我不确定规范中的 C++11 语言是否有能力编写那样的代码,但规范肯定会要求编译器做一些事情,规范中的语言不够强大.