Android系統(tǒng)中的同步機(jī)制

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ù)的邏輯語義如下

  1. 釋放mutex鎖
  2. 進(jìn)入休眠等待
  3. 喚醒后再獲取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: 被多個對象持有。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,283評論 6 530
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,947評論 3 413
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,094評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,485評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,268評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,817評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,906評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,039評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,551評論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,502評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,662評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,188評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,907評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,304評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,563評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,255評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,637評論 2 370

推薦閱讀更多精彩內(nèi)容