c – 在x64 CPU上读取原子16字节

我需要以16位字节读写.我做的只是使用cmpxchg16,这是所有x64处理器可用,除了我认为一个晦涩的AMD.

现在的问题是对齐16个字节的值,只有使用cmpxchg16(它的行为就像一个完整的内存屏障)才能修改,是否有可能读取一半的旧数据和一半的新数据的16位元的位置?

只要我用SSE指令读取(所以线程在读取的中间不能中断),我认为这是不可能的(即使在多处理器numa系统中)读取看到不一致的数据.我认为它必须是原子的.

我假设当执行cmpxchg16时,它以原子方式修改16个字节,而不是通过写入两个8字节的块,其中有可能为其他线程进行读取(老实说,我看不出它可以如何工作不是原子的)

我对吗?如果我错了,有没有办法做一个原子16字节读取而不诉诸锁定?

注意:有一个couple similar questions here,但是他们没有处理只用cmpxchg16完成写入的情况,所以我觉得这是一个单独的,未回答的问题.

编辑:其实我认为我的推理是错误的. SSE加载指令可以被执行为两个64位读取,并且可以通过另一个处理器在两次读取之间执行cmpxchg16.

解决方法

typedef struct
{
  unsigned __int128 value;
} __attribute__ ((aligned (16))) atomic_uint128;

unsigned __int128
atomic_read_uint128 (atomic_uint128 *src)
{
  unsigned __int128 result;
  asm volatile ("xor %%rax,%%rax;"
                "xor %%rbx,%%rbx;"
                "xor %%rcx,%%rcx;"
                "xor %%rdx,%%rdx;"
                "lock cmpxchg16b %1" : "=A"(result) : "m"(*src) : "rbx","rcx");
  return result;
}

这应该够了吧. typedef确保正确的对齐. cmpxchg16b需要在16字节边界上对齐数据.

cmpxchg16b将测试* src是否包含零,如果是(nop)则写入零.在任一情况下,正确的值将在RAX:RDX之后.

上面的代码评估为一样简单

push   %rbx
xor    %rax,%rax
xor    %rbx,%rbx
xor    %rcx,%rcx
xor    %rdx,%rdx
lock cmpxchg16b (%rdi)
pop    %rbx
retq

相关文章

/** C+⬑ * 默认成员函数 原来C++类中,有6个默认成员函数: 构造函数 析构函数 拷贝...
#pragma once // 1. 设计一个不能被拷贝的类/* 解析:拷贝只会放生在两个场景中:拷贝构造函数以及赋值运...
C类型转换 C语言:显式和隐式类型转换 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译...
//异常的概念/*抛出异常后必须要捕获,否则终止程序(到最外层后会交给main管理,main的行为就是终止) try...
#pragma once /*Smart pointer 智能指针;灵巧指针 智能指针三大件//1.RAII//2.像指针一样使用//3.拷贝问...
目录<future>future模板类成员函数:promise类promise的使用例程:packaged_task模板类例程...