我正在尝试验证不同intel CPU上128位操作的原子性,但是由于某种原因,我的程序在我测试的每台机器上都无法通过原子性测试。我已经在常春藤桥和Broadwell CPU上进行了测试。我已经在下面包含了源代码。基本上,它是同时增加两个64位计数器,这些计数器组合在一起形成128位整数。如果原子性在CPU上起作用,则低64位必须始终等于高64位。这就是该程序正在测试的内容。但是测试始终失败,并显示以下输出:
发现不一致的地方18550,18551
我正在运行ubuntu 4.15,gcc,我正在将此代码编译为:
g++ -pthread -march=native test.cc -latomic
代码如下:
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <thread>
__int128 __attribute__((__aligned__(16))) count;
void task() {
while(1) {
__int128 old_count, swapped_count;
do {
__atomic_load(&count, &old_count, __ATOMIC_SEQ_CST);
uint64_t old_lo = (uint64_t)old_count;
uint64_t old_hi = ((uint64_t)(old_count >> 64));
if (old_lo != old_hi) {
printf("Found inconsistency %lu, %lu\n", old_lo, old_hi);
exit(1);
}
__int128 __attribute__((__aligned__(16))) new_count;
new_count = old_hi + 1;
new_count <<= 64;
new_count |= (old_lo + 1);
swapped_count = __sync_val_compare_and_swap(&count, old_count, new_count);
uint64_t new_lo = (uint64_t)swapped_count;
uint64_t new_hi = (uint64_t)(swapped_count >> 64);
if (new_lo != new_hi) {
printf("Found inconsistency post swap %lu, %lu\n", new_lo, new_hi);
exit(1);
}
// At this point count must have changed one way or the other
if (count == old_count) {
printf("Count is still the same ????\n");
exit(1);
}
} while (old_count != swapped_count);
} // while (1)
}
int main() {
count = 0;
for (int i = 0; i < 2; i++)
new std::thread(task);
while(1)
sleep(1);
}
答案 0 :(得分:0)
所以我发现gcc不能以无锁方式实现16Byte原子。使用gdb进行调试后,我发现gcc中的__atomic * _16()函数使用了锁。另一方面,__sync * _16()函数使用lock cmpxchg16
指令。因此,马克的建议是正确的。您不能将__sync与__atomic混合使用,并且通常__atomic(特别是16字节操作)不是无锁的(还可以吗?)。
因此,我最终实现了针对16字节原子加载和CAS的自己的原语。我在下面粘贴该代码。使用这些原语,上面的代码即可正常工作。
union alignas(16) atomic_u128 {
unsigned __int128 val;
struct {
volatile uint64_t lo, hi;
};
};
// Atomically read a 128 bit unsigned.
__attribute__((always_inline)) inline unsigned __int128 AtomicLoad128(
register atomic_u128 *src) {
atomic_u128 ret;
__asm__ __volatile__ (
"xor %%ecx, %%ecx\n"
"xor %%eax, %%eax\n"
"xor %%edx, %%edx\n"
"xor %%ebx, %%ebx\n"
"lock cmpxchg16b %2"
: "=&a"(ret.lo), "=d"(ret.hi)
: "m"(*src)
: "cc", "rbx", "rcx" );
return ret.val;
}
__attribute__((always_inline)) inline bool AtomicCAS128(
volatile atomic_u128 *src, atomic_u128 *expected,
atomic_u128 desired) {
bool result;
atomic_u128 e;
e.val = expected->val;
__asm__ __volatile__ (
"lock cmpxchg16b %1"
: "=@ccz" ( result ), "+m" ( *src ), "+a"(e.lo), "+d"(e.hi)
: "c" ( desired.hi ), "b" ( desired.lo )
: "cc");
if (!result)
expected->val = e.val;
return result;
}