Android原子操作——android_atomic_cmpxchg
網絡給我們帶來了很多方便,查閱我們目前認知範圍外的道理。但是,凡事也要學會分辨,不然可能會誤導你。
話說,最近的一個項目(Mercury-Project),接近尾聲中。然而,在調試一個demo時,卻遇到了問題。
理一下問題由來:
1.目標:將Android下的一些基礎工具移植到純正Linux平台上用。
2.移植RefBase時,用到了原子操作:
android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong)
怎麼辦呢?因為這個api是Android實現的一套底層原子操作(應付並發場景下比較+交換操作的原子性要求),因此需要尋找通用Linux平台所對應的api。
是什麼呢?這個:__sync_bool_compare_and_swap(),其原型為:bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval)
需要注意的是,這個是gcc提供的api,而非OS提供的。
3.如何替換?
分析gcc的CAS的原型:bool __sync_bool_compare_and_swap(type *ptr, type oldval, type newval)
這個CAS函數,功能為:比較oldval與*ptr的值,如何相等,則用newval更新*ptr的值,否則不更新;當更新時,返回true,不跟新時,返回false。
Android的這個api原型:int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr)
然而,這個函數,網上一大片錯的!估計都沒驗證過,就抄過來抄過去。呵呵。。。
截取網上找到的兩段:
我也天真的相信了,移植時,將如下代碼:
if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0)
修改為了:
if (__sync_bool_compare_and_swap(&impl->mStrong, curCount, curCount+1) == 0)
4.問題出現:
在跑demo,驗證RefBase時,將對象進行promote時,等待了近一分鐘,才執行完!
回來查問題,才定位到,是這個CAS函數替換引入的!
5.api真正的功能是什麼?
參考api說明://androidxref.com/4.4.4_r1/xref/system/core/include/cutils/atomic.h#115
以及實現://androidxref.com/4.4.4_r1/xref/system/core/include/cutils/atomic-arm.h#108
截下來:
如果看不懂彙編,看最後一行的return語句,也猜的八九不離十:相等時,返回0;不等時,返回1。
這一段API接口說明要仔細讀:
110-112行說,這個兩個接口是新API(android_atomic_release_cas)的別名,在將來可能被移除掉,不建議再用此API。
再看95-96行的說明,返回zero,只有在*addr==oldvalue時,才發生!!!
第98行,補充說,在其他平台(非ARM平台)上,根據具體的實現,返回值是反的。