我正在使用SunOs在< sys / atomic.h>中提供的原子操作。 ,是
void *atomic_cas_ptr(volatile void *target, void *cmp, void *newval);
现在要使用是可用的,我必须检查此函数返回的旧值和被调用函数cmp传递的是否相同,如果它们是操作成功。
但我有一定的疑问:因为这个函数返回一个指向旧值的void指针让我们称之为void * old而我正在传递void * cmp,那么我需要比较这两个旧的和cmp,所以我将如何比较这两个 ?如果在比较* old时改变了那么我将要做什么?
本质上我想要做的是扭曲这个函数,在另一个函数中,它接受这三个参数并返回true或false,表示成功或失败。
关于CAS
,我读到它称之为无锁操作是错误的,因为它最终会锁定硬件(锁定总线),这是对的吗?这就是CAS操作成本高的原因。
答案 0 :(得分:2)
可能函数声明让你感到困惑。这个函数不会返回指向旧值(是什么?)的指针,而是指向target
指向的内存中的旧值(它应该是指向void *的指针,即void* volatile * target
)。
通常,如果CAS原语返回旧值而不是bool,则使用以下内容检查CAS成功:
void* atomic_ptr; // global atomically modified pointer
void* oldval, newval, comparand; // local variables
/* ... */
oldval = atomic_cas_ptr( (void*)&atomic_ptr, /* note that address is taken */
comparand, newval );
if( oldval == comparand ) {
// success
} else {
// failure
}
因此,当您比较old_val和comparand时,您将使用不会同时更改的局部变量(同时可能会再次更改全局atomic_ptr),并且您可以在不解除引用的情况下比较指针值。
你想要的功能应该是这样的:
bool my_atomic_cas_ptr(volatile void* target, void* comparand, void* newval)
{
return (comparand == atomic_cas_ptr(target, comparand, newval));
}
请注意,因为在某些算法中应该知道旧值(CAS之前的值),所以最好让CAS原语返回旧值而不是bool,因为您可以轻松地从前者创建后者。反面更复杂,效率更低(请参阅以下代码,尝试从返回bool的a MacOS CAS primitive中获取正确的旧值。)
void* CAS(void* volatile* target, void* comparand, void* newval)
{
while( !OSAtomicCompareAndSwapPtr(comparand, newval, target) ) {
void* snapshot = *target;
if( snapshot!=comparand ) return snapshot;
}
return comparand;
}
至于CAS锁存储器总线,它取决于硬件。对于旧的x86处理器来说确实如此,但在现代x86系统中却有所不同。首先,没有中央公交车;它被AMD的HyperTransport和英特尔的QuickPath Interconnect所取代。其次,在最近的CPU生成中,锁定的指令并非都是序列化的(参见some data表明不同存储器地址上的锁定指令不会干扰)。最后,在the commonly accepted definition锁定自由是整个系统进步的保证,而不是serializing synchronization的缺席。