2014-01-22 22 views
0

我正在使用一个64位x86系统,限制为最多8字节的比较和交换操作。由于指针是8字节,我需要一个计数器来避免ABA问题,是否可以修改指针的高16位,这些指针不用于存储计数器?只有8字节CAS锁定? C++

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函数存储修改的指针地址?

回答

2

好了,这是不保证按照你真的允许用指针转换成int做的是将它转换回不变的指针任何标准,唯一的工作。但实际上,它可以在任何x86_64平台以及其他几乎任何其他平台上运行。显然你并不期待特定于gcc的x86_64专用代码是可移植的。所以,这里没有问题。

此外,uintptr_t不是用于gcc原子功能的supported types--但它完全兼容unsigned long long int,它是。 (如果你担心这一点,你可以随时添加第二个演员...)所以,这里也没有问题。

同时,__sync_bool_compare_and_swap不关心你是走私在uintptr_t指针;就它而言,它只是一个无符号的64位整数。所以,这里没有问题。

你真的能肯定的是,前16位总是空的?在x86_64 linux中,它们是为了您的普通用户内存。他们可能不是指向核心内存或者内存映射的硬件,他们可能无法在其他x86_64系统,但如果没有,他们会全1代替。正如布伦丹指出的那样,这可以保证在没有128位CAS的x86_64硬件上运行任何东西。*因此,如果您需要将这些内存或端口指向这些系统,只需使用15位而不是16位。假设你指向的是64位对齐的对象,那么你在指针的另一端也有6个空闲位,你可以使用它来替代/另外使用)。问题也在这里。


*除了在高度万一AMD或英特尔或其他人决定改变虚拟地址的大小,也决定要带走128位CAS ...

+0

感谢您的答复,这是有益的。由于_sync_bool_cas需要一个指向内存位置的第一个参数,我怎么会通过(宁uint64_t中我已经投之后)的指针uintptr_t的变量本身存储在uintptr_t的数量,而不是? – user3217789

+0

@ user3217789:你不能使用被改写的行动伪装指针在'uintptr_t'为*指针*,你只能把它作为一个_value_。无论你有哪些结构引用了一些需要CAS'd的对象,你都会存储指针_there_,而不是实际的指针。然后你通过使用结构中的地址来CAS他们。而且你必须去掉这些部分才能去掉它们。 – abarnert

+0

@ user3217789:想一想,在指针本身上有一个计数器会有什么好处呢? CAS的全部重点是验证自上次检查以来指向的64位内存没有改变。没有人关心你是否有一个指向64位内存的新指针,就是那里。请记住,您首先需要CAS的全部原因是其他对象将具有指向同一地址的其他对象。 – abarnert