1. Overview
操作系統(tǒng)的同步機(jī)制都是類似的,目前Android封裝的同步類包括:
- Mutex
頭文件是frameworks/native/include/utils/Mutex.h
android 中的Mutex僅僅對pthread提供的API作了簡單的封裝,所以函數(shù)聲名和實現(xiàn)體都放在同一個頭文件中,方便調(diào)用者操作- Condition
頭文件是frameworks/native/include/utils/Condition.h
Condition是“條件變量”在android中的實現(xiàn)類,它實際上是依賴Mutex完成的- Barrier
頭文件是frameworks/native/include/utils/Barrier.h
Barrier是同時基于Mutex和Condition實現(xiàn)的一個模型。AudioFlinger和SurfaceFlinger都會碰到其使用場景。
2. 進(jìn)程間同步 Mutex
Mutex 頭部有一個emum:
enum {
PRIVATE = 0, //只限統(tǒng)一進(jìn)程間的同步
SHARED = 1 //支持跨進(jìn)程同步
};
這代表Mutex既可以處理進(jìn)程內(nèi)部的同步情況,也可以處理進(jìn)程間同步問題。
如果Mutex構(gòu)造的時候指定它的type是SHARED的話,它是適用于跨進(jìn)程共享的。
因為Mutex只有兩種狀態(tài),即0或1,所以這個類只提供了三個重要接口:
// lock or unlock the mutex
status_t lock();
void unlock();
// lock if possible; returns 0 on success, error otherwise
status_t tryLock();
當(dāng)調(diào)用者希望訪問臨界資源時,他必須現(xiàn)通過lock()
來獲得資源鎖,如果此時資源可用,則立即返回,否則進(jìn)入阻塞等待,直到有人釋放并喚醒它。釋放資源鎖調(diào)用unlock()
,同時正在等待使用這個鎖的其他對象就被喚醒,然后繼續(xù)執(zhí)行它的任務(wù)。
trylock()
:無論能不能獲取資源都不等待,而是立即返回嘗試加鎖的結(jié)果。若資源可用則返回成功(返回值為0);否則則返回失敗(返回值不為0)。
以上三個接口的實現(xiàn)如下:
#if defined(HAVE_PTHREADS)
......
......
inline status_t Mutex::lock() {
return -pthread_mutex_lock(&mMutex);
}
inline void Mutex::unlock() {
pthread_mutex_unlock(&mMutex);
}
inline status_t Mutex::tryLock() {
return -pthread_mutex_trylock(&mMutex);
}
#endif // HAVE_PTHREADS
可見Mutex其實只是基于pthread接口的再封裝。
3. 條件判斷:Condition
Condition通過判斷條件是否滿足來獲得資源。
- 如果滿足——馬上返回,繼續(xù)執(zhí)行未完成的動作。
- 如果不滿足——進(jìn)入休眠等待,知道條件滿足時有人喚醒它
Mutex與Condition的區(qū)別:
Mutex需要資源的獲取者主動發(fā)起查詢,當(dāng)發(fā)現(xiàn)條件滿足時獲取資源,而Condition會在判斷滿足條件時,主動通知處于等待狀態(tài)的線程。
Condition 接口源碼
class Condition {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
Condition();
Condition(int type);
~Condition();
// Wait on the condition variable. Lock the mutex before calling.
status_t wait(Mutex& mutex);
// same with relative timeout
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
// Signal the condition variable, allowing one thread to continue.
void signal();
// Signal the condition variable, allowing all threads to continue.
void broadcast();
private:
#if defined(HAVE_PTHREADS)
pthread_cond_t mCond;
#else
void* mState;
#endif
};
從Condition的接口函數(shù)中,可以看到:
- wait() 在等待某個條件滿足,如何描述這個條件?——它提供一個黑盒的方式來讓用戶來設(shè)定何種條件滿足。
- 為什么需要mutex?—— Barrier中提到原因,是由于condition自身的不完整性造成的。
4. Barrier
Barrier中文名為“柵欄,障礙”,它是一個填充了具體條件的Condition
Barrier是專門為SurfaceFlinger而設(shè)計的,并不是像Mutex,Condition一樣作為常用的Utility提供給整個Android系統(tǒng)使用。
Barrier接口源碼
class Barrier
{
public:
inline Barrier() : state(CLOSED) { }
inline ~Barrier() { }
// Release any threads waiting at the Barrier.
// Provides release semantics: preceding loads and stores will be visible
// to other threads before they wake up.
void open() {
Mutex::Autolock _l(lock);
state = OPENED;
cv.broadcast();
}
// Reset the Barrier, so wait() will block until open() has been called.
void close() {
Mutex::Autolock _l(lock);
state = CLOSED;
}
// Wait until the Barrier is OPEN.
// Provides acquire semantics: no subsequent loads or stores will occur
// until wait() returns.
void wait() const {
Mutex::Autolock _l(lock);
while (state == CLOSED) {
cv.wait(lock);
}
}
private:
enum { OPENED, CLOSED };
mutable Mutex lock;
mutable Condition cv;
volatile int state;
};
Barrier 提供了三個接口函數(shù):wait()
, close()
, open()
其condition就是 state,有OPENED和CLOSED兩個狀態(tài);上面三個函數(shù)都是先獲取一個Mutex鎖,以保證對state資源的占有是互斥使用的,然后再調(diào)用Condition中的wait()函數(shù)。
Condition中的wait函數(shù)實現(xiàn):
inline status_t Condition::wait(Mutex& mutex) {
return -pthread_cond_wait(&mCond, &mutex.mMutex);
}
pthread_cond_wait()
函數(shù)的邏輯語義如下
- 釋放mutex鎖
- 進(jìn)入休眠等待
- 喚醒后再獲取mutex鎖
釋放再喚醒mutex鎖的操作,是為了讓其它進(jìn)程在open()/close()的時候可以獲取到state資源,以免造成死鎖。
wait()函數(shù)結(jié)尾會自動釋放mutex鎖,因為_l是一個AutoLock,也就是說,在等待結(jié)束時,程序會結(jié)束針對共享資源的持鎖了。如果后續(xù)再有對共享資源的操作,應(yīng)該重新再加鎖。
因為以上特性,Barrier通常被用于線程初始化的判斷,這種場景具有不可逆性,也就是說,被初始化之后,后期不可能再出現(xiàn)“沒有初始化”的情況了,這時wait()結(jié)束后不再持鎖,也是安全的了。
5.Autolock:加解鎖自動化操作
Autolock時Mutex里的一個嵌套類,實現(xiàn)代碼:
class Autolock {
public:
inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
inline ~Autolock() { mLock.unlock(); }
private:
Mutex& mLock;
};
Autolock構(gòu)造時,主動調(diào)用內(nèi)部成員變了mLock的lock()函數(shù)來獲取一個鎖,而析構(gòu)的時候,正好相反,調(diào)用unlock(),這樣當(dāng)他生命周期結(jié)束的時候就會自動解開對資源的鎖。
6. ReaderWriterMutex:讀寫鎖
Android Art 虛擬機(jī)中用到互斥和鎖操作的地方非常多,為此它實現(xiàn)了一整套自己的mutex機(jī)制,可以參考art/runtime/base 目錄了解。
ReaderWriterMutex是art虛擬機(jī)中一個特殊的mutex,它是“讀寫鎖”的意思,它提供了一下接口:
class LOCKABLE ReaderWriterMutex : public BaseMutex {
public:
// Block until ReaderWriterMutex is free then acquire exclusive access.
void ExclusiveLock(Thread* self) EXCLUSIVE_LOCK_FUNCTION();
void WriterLock(Thread* self) EXCLUSIVE_LOCK_FUNCTION() {
ExclusiveLock(self); }
// Release exclusive access.
void ExclusiveUnlock(Thread* self) UNLOCK_FUNCTION();
void WriterUnlock(Thread* self) UNLOCK_FUNCTION() { ExclusiveUnlock(self); }
// Block until ReaderWriterMutex is shared or free then acquire a share on the access.
void SharedLock(Thread* self) SHARED_LOCK_FUNCTION();
void ReaderLock(Thread* self) SHARED_LOCK_FUNCTION() { SharedLock(self); }
// Release a share of the access.
void SharedUnlock(Thread* self) UNLOCK_FUNCTION();
void ReaderUnlock(Thread* self) UNLOCK_FUNCTION() { SharedUnlock(self); }
}
從上面的接口可以看到,art中的的Exclusive和Shared分別代表的是write和read權(quán)限,也可以看出:它可以允許有多個對象共享Read鎖,但只能有唯一的對象持有Write鎖。
ReaderWriterMutex有以下三種狀態(tài):
- Free: 沒有被任何對象持有
- Exclusive: 當(dāng)前被唯一對象持有
- Shared: 被多個對象持有。