http://www.liblfds.org/wordpress/
/liblfds6.1.1/liblfds611/src/lfds611_abstraction/lfds611_abstraction_dcas.c
static LFDS611_INLINE unsigned char lfds611_abstraction_dcas( volatile lfds611_atom_t *destination, lfds611_atom_t *exchange, lfds611_atom_t *compare )
{
unsigned char
cas_result;
assert( destination != NULL );
assert( exchange != NULL );
assert( compare != NULL );
// TRD : __asm__ with "memory" in the clobber list is for GCC a full compiler barrier
__asm__ __volatile__
(
"lock;" // make cmpxchg16b atomic
"cmpxchg16b %0;" // cmpxchg16b sets ZF on success
"setz %3;" // if ZF set, set cas_result to 1
// output
: "+m" (*(volatile lfds611_atom_t (*)[2]) destination), "+a" (*compare), "+d" (*(compare+1)), "=q" (cas_result)
// input
: "b" (*exchange), "c" (*(exchange+1))
// clobbered
: "cc", "memory"
);
return( cas_result );
}
http://stackoverflow.com/questions/20113375/implement-double-word-cas-by-assambly
裡面的 組合語言 語法不一樣 ....
另外 , liblfds 提到 CAS 使用 "cache line lock" 方式 來運作 , 也就是說 ,CAS 搶到的那個 core
lock Compare 的 var , 當完成時 該 var 其他 core cache 的內容被 invalidate ,
搶失敗的 core 必須重讀 var 並且再作一次 CAS , __sync_add_and_fetch RMW 有 memory barrier 特性,
CAS 也能是個 memory barrier , 例如 :
Thread1 :
x = 1 ;
r1 = y ;
Thread2 :
y = 1 ;
r2 = x ;
就算 intel 也可能出現 r1==0 && r2==0 的結果
然而 :
T1 :
x = 1 ;
CAS var1
r1 = y ;
T2 :
y = 1 ;
CAS var2
r2 = x ;
這裡 CAS 在不相關變數 , 但是 不再出現 r1==0 && r2==0 的結果 , CAS 是 full memory barrier ,
也就是 acquire - release barrier , 所以 , store/load sequential is fine !!!!
重點 : CAS implement "cache line lock" 所以該變數的 cache line 必須 在該 core L1 cache 才能作 CAS ,
做完之後 , 因為 memory barrier 關係, 該 core 所有 write buffer 的 data 將被 FIFO flush !!
其他 core 的 該 cache line 將被 invalidated , 要繼續作 CAS , 如使用相同 L1 cache 因為沒被 invalidated
所以很快就能作 , 不同 L1 cache 的 core 必須從 memory 重讀 或是從 有最新 cache line 那顆 core
的 bus 將該 cache line 傳過來 !!!!
留言列表