我使用 Linux x86_64 和 clang 3.3。
这在理论上是可能的吗?
std::atomic<__int128_t>
不起作用(对某些函数的未定义引用)。
__atomic_add_fetch
也不起作用('错误:还不能编译这个原子库调用')。
两者都std::atomic
适用__atomic_add_fetch
于 64 位数字。
我使用 Linux x86_64 和 clang 3.3。
这在理论上是可能的吗?
std::atomic<__int128_t>
不起作用(对某些函数的未定义引用)。
__atomic_add_fetch
也不起作用('错误:还不能编译这个原子库调用')。
两者都std::atomic
适用__atomic_add_fetch
于 64 位数字。
用一条指令不可能做到这一点,但你可以模拟它并且仍然是无锁的。除了最早的 AMD64 CPU,x64 支持CMPXCHG16B
指令。用一点多精度数学,你可以很容易地做到这一点。
恐怕我不知道CMPXCHG16B
GCC 中的 intrinsic for,但希望你能理解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 指令可以在一条指令中执行 128 位相加,并且要以原子方式执行某些操作,基本起点是它是一条指令(即使在那时有些指令也不是原子的,但那是另一件事)。
您将需要在 128 位数字周围使用其他锁。
编辑:有人可能会想出一些使用这样的东西:
__volatile__ __asm__(
" mov %0, %%rax\n"
" mov %0+4, %%rdx\n"
" mov %1,%%rbx\n"
" mov %1+4,%%rcx\n"
"1:\n
" add %%rax, %%rbx\n"
" adc %%rdx, %%rcx\n"
" lock;cmpxcchg16b %0\n"
" jnz 1b\n"
: "=0"
: "0"(&arg1), "1"(&arg2));
那只是我刚刚破解的东西,我还没有编译它,更不用说验证它会起作用了。但原则是它重复,直到它比较相等。
Edit2:该死的打字太慢了,Cory Nelson 刚刚发布了同样的内容,但使用了 intrisics。
Edit3:将循环更新为不需要读取的不必要的读取内存...... CMPXCHG16B 为我们做到了。
是的; 你需要告诉你的编译器你在支持它的硬件上。
这个答案将假设您使用的是 x86-64;手臂可能有类似的规格。
从通用 x86-64微体系结构级别,您至少x86-64-v2
希望让编译器知道您拥有该cmpxchg16b
指令。
这是一个工作的godbolt,注意编译器标志-march=x86-64-v2
:
https ://godbolt.org/z/PvaojqGcx
有关 x86-64-psABI 的更多信息,请参阅此处发布的规范。