如何在C++中原子地添加和获取128位数字
How to atomically add and fetch a 128-bit number in C++?
我使用Linux x86_64和clang 3.3。
这在理论上可能吗?
std::atomic<__int128_t>
不起作用(对某些函数的未定义引用)。
__atomic_add_fetch
也不起作用("错误:还不能编译这个原子库调用")。
CCD_ 3和CCD_。
用一条指令是不可能做到这一点的,但您可以模拟它,并且仍然没有锁。除了最早的AMD64 CPU外,x64支持CMPXCHG16B
指令。只要有一点多精度数学,你就可以很容易地做到这一点。
恐怕我不知道GCC中CMPXCHG16B
的本质,但希望你能想到CMPXCHG16B
的自旋环。以下是一些未经测试的VC++代码:
// atomically adds 128-bit src to dst, with src getting the old dst.
void fetch_add_128b(uint64_t *dst, uint64_t* src)
{
uint64_t srclo, srchi, olddst[2], exchlo, exchhi;
srchi = src[0];
srclo = src[1];
olddst[0] = dst[0];
olddst[1] = dst[1];
do
{
exchlo = srclo + olddst[1];
exchhi = srchi + olddst[0] + (exchlo < srclo); // add and carry
}
while(!_InterlockedCompareExchange128((long long*)dst,
exchhi, exchlo,
(long long*)olddst));
src[0] = olddst[0];
src[1] = olddst[1];
}
编辑:这里有一些未经测试的代码,我可以为GCC内部找到:
// atomically adds 128-bit src to dst, returning the old dst.
__uint128_t fetch_add_128b(__uint128_t *dst, __uint128_t src)
{
__uint128_t dstval, olddst;
dstval = *dst;
do
{
olddst = dstval;
dstval = __sync_val_compare_and_swap(dst, dstval, dstval + src);
}
while(dstval != olddst);
return dstval;
}
是;你需要告诉你的编译器你在支持它的硬件上。
这个答案将假设您使用的是x86-64;arm可能也有类似的规格。
从通用x86-64微体系结构级别来看,您至少需要x86-64-v2
让编译器知道您有cmpxchg16b
指令。
这是一个工作的godbolt,请注意编译器标志-march=x86-64-v2
:https://godbolt.org/z/PvaojqGcx
有关x86-64-psABI的更多信息,请在此处发布规范。
这是不可能的。没有一条x86-64指令可以在一条指令中添加128位,而要原子化地做一些事情,一个基本的起点是它是一条指令(有些指令即使在那时也不是原子性的,但那是另一回事)。
您需要在128位数字周围使用一些其他锁。
编辑:有可能有人会想出这样的东西:
__volatile__ __asm__(
" mov %0, %%raxn"
" mov %0+4, %%rdxn"
" mov %1,%%rbxn"
" mov %1+4,%%rcxn"
"1:n
" add %%rax, %%rbxn"
" adc %%rdx, %%rcxn"
" lock;cmpxcchg16b %0n"
" jnz 1bn"
: "=0"
: "0"(&arg1), "1"(&arg2));
这只是我刚刚破解的东西,我还没有编译它,更不用说验证它是否有效了。但原则是,它会重复,直到比较相等。
编辑2:Darn打字太慢了,Cory Nelson只是发布了同样的东西,但使用了一些有趣的东西。
第3版:将循环更新为不需要读取的不必要的读取内存。。。CMPXCHG16B为我们做到了这一点。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- C++为构建时间获取QDateTime的可靠方法
- 如何在C++中从两个单独的for循环中添加两个数组
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何获取多类型向量中的值(不添加 <type>)?
- 如何在C++中获取子字符串并在字符串之间添加字符
- 我在C++从函数中的用户获取输入、添加到数组和打印该数组时遇到问题
- C++Arduino:从hashmap添加和获取值会返回垃圾值
- 尝试将对象添加到向量时,获取错误C2280
- 如何从文件夹中获取文件名,并将它们添加到QT中的孩子中
- EntityX-获取添加到系统中的新实体
- 将opencv库添加到QT创建者并获取错误:链接器命令失败,退出代码为1
- 我将Sprite添加到CCArray,但是如何通过CCObject获取其成员,例如getPosition()
- 如何在C++中原子地添加和获取128位数字
- 从QMap获取最后插入/添加的项目
- 向CMFCPropertyGridCtrl添加/获取值
- C /c++获取要添加到已排序数组的元素的索引
- 如何使用Inotify和libev在文件夹中获取新添加的文件
- 从地图中获取项目并添加到向量c++中
- 模板.添加,获取元素char*