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平台)上,根據具體的實現,返回值是反的。