我在<sys/atomic.h>,是 void *atomic_cas_ptr(volatile void *target, void *cmp, void *newval);
现在,为了使其可用,我必须检查此函数返回的旧值和被调用者函数cmp传递的旧值是否相同,如果相同,则操作成功
但我有一定的疑问:因为这个函数返回一个指向旧值的void指针,我们称之为void*old,并且我正在传递void*cmp,所以我需要比较这两个old和cmp,那么我将如何比较这两者呢?如果在比较旧的时候发生了变化,我该怎么办
本质上,我想做的是在另一个函数中扭曲这个函数,这个函数接受这三个参数并返回true或false,这表示成功或失败。
关于CAS
,我读到称其为无锁定操作用词不当,因为它最终在硬件上锁定(在总线上锁定),这是正确的吗?这就是为什么CAS的运营成本很高。
函数声明可能让您感到困惑。此函数不返回指向旧值(什么?)的指针,而是返回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的MacOS CAS原语中获得正确的旧值)。
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中,锁定指令并不是全部序列化的(请参阅一些数据,这些数据显示不同内存地址上的锁定指令不会干扰)。最后,在公认的定义中,锁定自由是全系统进步的保证,而不是缺乏串行化同步。