我使用的 64 位 x86 系统限制为最多 8 个字节用于比较和交换操作。由于指针是 8 字节,我需要一个计数器来避免 ABA 问题,是否可以修改未用于存储计数器的指针的高 16 位?
pointer_as_dec = reinterpret_cast<uintptr_t>(&node); // Node address
pointer_as_dec+(1LLU<<48); // Initialize the counter in one of the upper bits
是否可以使用__sync_bool_compare_and_swap函数来存储修改后的指针地址?
最佳答案
好吧,这不能保证根据任何标准工作——您真正允许将指针转换为 int 的唯一事情是将其原封不动地转换回指针。但实际上,它可以在任何 x86_64 平台和几乎任何其他当前平台上运行。显然,您并不期望特定于 gcc、特定于 x86_64 的代码是可移植的。所以,这里没问题。
此外,uintptr_t
不是 supported types 之一对于 gcc 原子函数——但它与 unsigned long long int
完全兼容,也就是。 (如果您担心这一点,您可以随时添加第二个 Actor ……)所以,这里也没有问题。
与此同时,__sync_bool_compare_and_swap
并不关心您是否在那个 uintptr_t
中走私指针;就它而言,它只是一个无符号的 64 位整数。所以,这里没问题。
你真的能确定前 16 位总是空的吗?在 x86_64 linux 中,它们用于您的普通用户内存。它们可能不用于指向内核内存或内存映射硬件的指针,并且它们可能不在其他 x86_64 系统上——但如果不是,它们将全部为 1。正如 Brendan 指出的那样,在没有 128 位 CAS 的 x86_64 硬件上运行的任何东西都可以得到保证。*因此,如果您需要指向此类系统的此类内存或端口,只需使用 15 位而不是 16 位。(即使那不是真的,假设你指向的是 64 位对齐的对象,你在指针的另一端也有 6 个空闲位,你可以使用它来代替/另外使用。)所以,不这里也有问题。
* 除非 AMD 或 Intel 或其他人决定更改虚拟地址大小并且还决定取消 128 位 CAS 的可能性极小......
关于c++ - 仅使用 8 字节 CAS 无锁? C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21274053/