Android 原子操作函數介紹

来源:互联网 发布:apache hadoop 官网 编辑:程序博客网 时间:2024/06/06 01:35
原子操作函數介紹
什麼是原子操作?所謂原子操作,就是該操作絕不會在執行完畢前被任何其他任務或事件打斷,也就說,原子操作是最小的執行單位。
上面這句話放到代碼中是什麼意思?請看一個例子:
[-->例子]
static int g_flag = 0; //全局變量g_flag
static Mutex  lock  ;//全局的锁
//線程1執行thread1。
void thread1()
{
   //g_flag遞減,每次操作前锁住。
   lock.lock();
   g_flag--;
   lock.unlock();
}
//線程2中執行thread2函數。
void thread2()
{
   lock.lock();
   g_flag++; //線程2對g_flag進行遞增操作,每次操作前要取得锁。
   lock.unlock();
}
为什麼需要Mutex來幫忙呢?因为g_flags++或g_flags--操作都不是原子操作。從匯編指令的角度看,C/C++中的一條語句對應了數條匯編指令。以g_flags++操作为例,它生成的匯編指令可能就是以下三條:
 從內存中取數據到寄存器。
 對寄存器中的數據進行遞增操作,結果還在寄存器中。
 寄存器的結果寫回內存。

這三條匯編指令,如果按正常的順序連續執行是沒有問題的,但在多線程時就不能保證了。例如,線程1在執行第一條指令後,線程2由於調度的原因,搶在線程1之前連續執行完了三條指令。這样,線程1繼續執行指令時,它所使用的值就不是線程2更新後的值,而是之前的舊值。再對這個值進行操作便沒有意義了。
在一般情況下,處理這種問題可以使用Mutex來加锁保護,但Mutex的使用方法比它所要保護的內容還要复雜,例如,锁的使用將導致從用戶態轉入內核態,有較大的浪費。那麼,有沒有簡便些的辦法讓這些加、減等操作不被中斷呢?
答案是肯定的,但這需要CPU的支持。在X86平台上,一個遞增操作可以用下面的內嵌匯編語句來實現:
#define LOCK "lock;"
INT32 InterlockedIncrement(INT32* lpAddend)
{
  /*
   這是我們在Linux平台上實現Windows API時使用的方法。
   其中在SMP系統上,LOCK定義成"lock;"表示锁總線,這样同一時刻就只能有一個CPU訪問總線了。
   非SMP系統,LOCK定義成空。由於InterlockedIncrement要返回遞增前的舊值,所以我們
   使用了xaddl指令,它先交換源和目的的操作數,再進行遞增操作。
*/
INT32 i = 1;
__asm__ __volatile__(
LOCK "xaddl %0, %1"
:"+r" (i), "+m" (*lpAddend)
: : "memory");
return *lpAddend;

}


Android的院子操作函数

Android提供了相關的原子操作函數。這裏有必要介紹一下各個函數的作用。
[-->Atomic.h],注意該文件位於system/core/include/cutils目錄中。
//原子賦值操作,結果是*addr=value。
voidandroid_atomic_write(int32_t value, volatile int32_t* addr);
//下面所有函數的返回值都是操作前的舊值。
//原子加1和原子減1。
int32_tandroid_atomic_inc(volatile int32_t* addr);
int32_tandroid_atomic_dec(volatile int32_t* addr);
//原子加法操作,value为被加數。
int32_tandroid_atomic_add(int32_t value, volatile int32_t* addr);
//原子“與”和“或”操作。
int32_tandroid_atomic_and(int32_t value, volatile int32_t* addr);
int32_tandroid_atomic_or(int32_t value, volatile int32_t* addr);
/*
條件交換的原子操作。只有在oldValue等於*addr時,才會把newValue賦值给*addr。
這個函數的返回值須特別注意。返回值非零,表示沒有進行賦值操作。返回值为零,表示
進行了原子操作。
*/
intandroid_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue,
                                volatile int32_t* addr);
有興趣的話,讀者可以對上述函數的實現進行深入研究,其中:
X86平台的實現在system/core/libcutils/Atomic.c中,注意其代碼在#elif defined(__i386__) || defined(__x86_64__)所包括的代碼段內。
ARM平台的實現在system/core/libcutils/atomic-android-arm.S匯編文件中。
原子操作的最大好處在於避免了锁的使用,這對整個程序運行效率的提高有很大幫助。目前,在多核並行編程中,最高境界就是完全不使用锁。當然,它的難度可想而知是巨大的。
原创粉丝点击