使用C ++ 11 <atomic>
库,只需使用atomic<T>::compare_and_exchange_X
的16字节类型,即可通过普通T
函数族利用双字CAS 。如果架构实际上不支持双字CAS,编译器将依赖于自旋锁。
双字CAS的常见用法是标记指针的实现 - 带有额外计数器值的指针,以避免困扰许多无锁数据结构的ABA problem和算法
然而 - 许多无锁算法的专业实现(例如Boost.Lockfree)实际上并没有使用双字CAS - 相反,它们依赖于单字CAS并选择使用非便携式指针填充恶作剧。由于x86_64架构仅使用指针的前48位,因此可以使用hi 16位填充计数器。
当然,据我所知,指针填充技术仅适用于x86_64 - 其他64位架构并不一定能保证高16位可用。另外,16位计数器只给你一个65536的最大值,所以理论上,在一些荒谬的病态情况下,如果一个线程被抢占然后另一个线程以某种方式执行超过65,536的话,ABA问题仍然会发生。在原始线程再次唤醒之前的操作(我知道,我知道,这是一个非常不可能的情况 - 但仍然比计数器变量是64位的情况更可能......)
由于上述考虑,似乎在某些架构上支持IF双字CAS,标记指针实现应该更喜欢使用包含实际指针和计数器变量的16字节指针结构,而不是8字节填充指针。
但是......有没有办法在编译时确定是否支持 CMPXCHG16B
?我知道大多数现代x86_64平台都支持它,但有些旧的计算机不支持它。因此,理想的做法是检查是否支持双字CAS,如果是,则使用16字节指针。如果没有,请回到8字节的填充指针。
那么,是否有任何方法可以实际检查(通过某些#ifdef
)是否支持CMPXCHG16B
?