《Android內(nèi)核設(shè)計(jì)思想》(一)進(jìn)程間的通信

進(jìn)程間通信(Inter-process communication, IPC)

? ?操作系統(tǒng)的進(jìn)程通常擁有獨(dú)立的內(nèi)存空間,并通過(guò)嚴(yán)格的機(jī)制防止進(jìn)程間的非法訪問(wèn)。進(jìn)程間的信息交流就需要進(jìn)程間通訊實(shí)現(xiàn)信息互通。

共享內(nèi)存

? ?共享內(nèi)存是常用的進(jìn)程間通信機(jī)制,其實(shí)現(xiàn)方法是兩個(gè)進(jìn)程直接共享訪問(wèn)一塊內(nèi)存區(qū)域。一般情況下,實(shí)現(xiàn)共享內(nèi)存的步驟如下:
1.創(chuàng)建內(nèi)存共享區(qū),進(jìn)程A通過(guò)操作系統(tǒng)提供的API從內(nèi)存中申請(qǐng)一塊共享區(qū)域。
2.將內(nèi)存共享區(qū)映射到進(jìn)程A的空間中
3.進(jìn)程B將內(nèi)存映射到自己的空間中
4.共享內(nèi)存的各個(gè)進(jìn)程實(shí)現(xiàn)內(nèi)存映射后通過(guò)該內(nèi)存區(qū)域進(jìn)行信息交換
5.完成進(jìn)程間通信后,各進(jìn)程撤銷(xiāo)之前的映射操作,然后刪除共享內(nèi)存區(qū)域。

管道

? ?管道也是操作系統(tǒng)的常見(jiàn)的進(jìn)程間通信方式,適用于所有POSIX系統(tǒng)及Windows系列產(chǎn)品。管道形象的形容了進(jìn)程間的行為,進(jìn)程A和B分立管道的兩邊,進(jìn)行數(shù)據(jù)的傳輸通信。管道是單向的,意味著一個(gè)進(jìn)程完成讀寫(xiě)兩個(gè)操作的時(shí)候需要建立兩根管道。管道有著容量限制,當(dāng)pipe滿(mǎn)時(shí)寫(xiě)操作將被阻塞;當(dāng)pipe空時(shí)讀操作將被阻塞。
? ?管道常用于父子進(jìn)程這種特殊的進(jìn)程關(guān)系,如果兩個(gè)進(jìn)程沒(méi)有任何關(guān)系,則無(wú)法通過(guò)管道是實(shí)現(xiàn)信息通信。這也是命名管道(Named Pipe)得以發(fā)展的原因。命名管道是服務(wù)器進(jìn)程和一個(gè)或多個(gè)客戶(hù)進(jìn)程之間通信的單向或雙向管道。不同于匿名管道的是:命名管道可以在不相關(guān)的進(jìn)程之間和不同計(jì)算機(jī)之間使用,服務(wù)器建立命名管道時(shí)給它指定一個(gè)名字,任何進(jìn)程都可以通過(guò)該名字打開(kāi)管道的另一端,根據(jù)給定的權(quán)限和服務(wù)器進(jìn)程通信。

2Unix Domain Socket(UDC)

? ?基于TCP/IP協(xié)議的Socket廣泛應(yīng)用于通信領(lǐng)域,也被稱(chēng)為Network Socket。UNIX Domain Socket是針對(duì)單機(jī)內(nèi)的進(jìn)程間通信提出來(lái)的,有時(shí)也被稱(chēng)為IPC Socket。UDS的基本流程與傳統(tǒng)Socket一致,以下提供了一個(gè)UDS的范例,其功能如下:

  • 服務(wù)器端監(jiān)聽(tīng)I(yíng)PC請(qǐng)求
  • 客戶(hù)端發(fā)起IPC請(qǐng)求
  • 雙方成功建立IPC連接
  • 客戶(hù)端向服務(wù)器端發(fā)送數(shù)據(jù),證明IPC通信是有效的
    建立UDC的過(guò)程相對(duì)繁瑣,通過(guò)soketpair()函數(shù)可以大大地簡(jiǎn)化通信雙方地工作。

Remote Procedure Calls

? ?RPC涉及的通信雙方通常運(yùn)行于兩臺(tái)不同的機(jī)器中,一個(gè)完整的RPC通信需要以下幾個(gè)步驟:
1.客戶(hù)端進(jìn)程調(diào)用Stub接口
2.Stub根據(jù)操作系統(tǒng)的要求進(jìn)行打包,并執(zhí)行相應(yīng)的系統(tǒng)調(diào)用
3.由內(nèi)核完成與服務(wù)器端的具體交互,將客戶(hù)端的數(shù)據(jù)包發(fā)送給服務(wù)器端的內(nèi)核
4.服務(wù)器端Stub解包并調(diào)用與數(shù)據(jù)包相匹配的進(jìn)程
5.進(jìn)程進(jìn)行操作
6.服務(wù)器以上述步驟的逆向過(guò)程將結(jié)果返回給客戶(hù)端
? ?

同步機(jī)制

? ?操作系統(tǒng)支持多線程的并發(fā)執(zhí)行,則它們之間難免出現(xiàn)相互制約的情況。例如兩個(gè)進(jìn)程需要共享唯一的硬件設(shè)備,或者一個(gè)進(jìn)程的工作依賴(lài)于另一方對(duì)共享資源的執(zhí)行結(jié)果。同步機(jī)制不但是操作系統(tǒng)的實(shí)現(xiàn)重點(diǎn),在應(yīng)用程序的設(shè)計(jì)也具有舉足輕重的作用。
? ?如果多個(gè)進(jìn)程間存在時(shí)序關(guān)系,需要協(xié)同工作以完成一項(xiàng)內(nèi)務(wù),稱(chēng)為同步。如果并不滿(mǎn)足協(xié)同的條件,而只是應(yīng)為共享具有排他性的資源時(shí)所產(chǎn)生的關(guān)系,則稱(chēng)為互斥。

信號(hào)量

? ?信號(hào)量是最為廣泛的互斥方法之一,它包括以下幾個(gè)元素:Semaphore S 信號(hào)量、Operation P(wait函數(shù)), Operation V(signal函數(shù))。信號(hào)量S用于指示共享資源的可用數(shù)量,P原語(yǔ)可以減少S計(jì)數(shù),V則增加它的計(jì)數(shù)。

Mutex

? ?
? ?Mutex是Mutual Exclusion的縮寫(xiě),其釋義為互斥體。Mutex通常是對(duì)某一排他資源的共享控制——要么這個(gè)資源被占用(locked),要么資源可以被訪問(wèn)(unlocked)。Mutex和Binary Semaphore機(jī)制沒(méi)有本質(zhì)差異。

管程(Monitor)

? ?管程是可以被多個(gè)進(jìn)程/線程安全訪問(wèn)的對(duì)象(object)或模塊(module)。Semaphore機(jī)制的程序可讀性相對(duì)較差,對(duì)于信號(hào)量的管理也分散在各個(gè)參與對(duì)象中,因此可能引發(fā)死鎖或進(jìn)程餓死等問(wèn)題。為了使資源的互斥訪問(wèn)更利于維護(hù),科學(xué)家們提出了管程的概念。管程中的方法都是受Mutual Exclusion保護(hù),同一時(shí)刻只允許有一個(gè)訪問(wèn)者使用它們,此外,管程還具有如下屬性:安全性、互斥性、共享性。

Linux Futex

? ?Futex(Fast Userspace muTEXes)是由Hubertus Franke等人發(fā)明的同步機(jī)制,其核心又是即為“fast”,主要體現(xiàn)在它在應(yīng)用程序空間中就可以應(yīng)對(duì)大多數(shù)的同步場(chǎng)景,從而減少系統(tǒng)調(diào)用和上下文切換的時(shí)間。Futex在Android中的一個(gè)重要應(yīng)用場(chǎng)景是ART虛擬機(jī)。對(duì)于不存在競(jìng)爭(zhēng)的場(chǎng)景下,futex機(jī)制可以在用戶(hù)態(tài)完成鎖的獲取。

? ?

Android的同步機(jī)制

? ?無(wú)論是什么操作系統(tǒng),其同步機(jī)制的技術(shù)本質(zhì)都是類(lèi)似的。目前Android封裝的同步類(lèi)包括: Mutex,Condition和Barrier。Mutex的頭文件是frameworks/native/include/utils/Mutex.h,Android中的Mutex只是對(duì)pthread提供的api的簡(jiǎn)單再封裝,所以函數(shù)聲明和實(shí)現(xiàn)體都放在同一個(gè)頭文件中,此外Mutex還包含一個(gè)Autolock的嵌套類(lèi),它是利用變量生命周期特點(diǎn)而設(shè)計(jì)的一個(gè)輔助類(lèi)。Condition是“條件變量”再Android中的實(shí)現(xiàn)類(lèi),其頭文件是framework/native/include/utils/Condition.h。Barrier是同時(shí)基于Mutex和Condition實(shí)現(xiàn)的一個(gè)模型,其頭文件是framework/native/include/utils/Barrier.h。

Condition

? ?Condition的核心思想是判斷“條件是否已經(jīng)滿(mǎn)足”,滿(mǎn)足時(shí)馬上返回,繼續(xù)執(zhí)行未完成的動(dòng)作,否則進(jìn)入休眠等待,指導(dǎo)條件滿(mǎn)足時(shí)有人喚醒。

Barrier

? ?Barrier表示“柵欄、障礙”,即Barrier是填充了具體條件的Condition。Barrier類(lèi)是專(zhuān)門(mén)為SurfaceFlinger設(shè)計(jì)的,并不是像Mutex和Condition是作為常用的Utility提供給整個(gè)Android系統(tǒng)使用。Barrier總共提供了3個(gè)接口函數(shù): wait(),open()和close()?!皸l件”是代碼中的state==OPENED,另一個(gè)狀態(tài)是CLOSED,這有嗲類(lèi)似于汽車(chē)柵欄的開(kāi)啟和關(guān)閉。當(dāng)汽車(chē)通過(guò)前,必須先確認(rèn)柵欄是開(kāi)啟的,于是調(diào)用wait(),當(dāng)條件不滿(mǎn)足時(shí),汽車(chē)需要停下來(lái)等待,函數(shù)首先獲得一個(gè)Mutex鎖,然后調(diào)用Condition對(duì)象,這是因?yàn)閟tate是互斥資源。

class Barrier{
public:
   inline Barrier(): state(CLOSED) {}
   inline ~Barrier() {} 
   void open() {
           Mutex::Autolock _l(lock);
           state = OPENED;
           cv.broadcast();
    }
    void close() {
            Mutex::Autolock _l(lock);
            state = CLOSED; 
     }
     void wait() const {
             Mutex::Autolock _l(lock);
             while(state == CLOSED) {
                     cv.wait(lock);
             }
     }
private:
      enum {OPENED, CLOSED};
       mutable Mutex lock;
       mutable Conditon cv;
       volatile int state;       
};

Autolock

? ?在Mutex類(lèi)的內(nèi)部有一個(gè)Autolock的嵌套類(lèi),它是為了實(shí)現(xiàn)加、解鎖的自動(dòng)化操作,這個(gè)類(lèi)的構(gòu)造和析構(gòu)函數(shù)如下:

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;
};

? ?當(dāng)Autolock構(gòu)造時(shí)會(huì)自動(dòng)調(diào)用成員變量mLock的lock()方法來(lái)獲得鎖,析構(gòu)時(shí)調(diào)用unlock()方法釋放鎖,這樣當(dāng)Autolock對(duì)象的生命周期結(jié)束時(shí)就會(huì)自動(dòng)把資源鎖解。

Reader WriterMutex

? ?Android Art虛擬機(jī)中用到互斥和鎖操作的地方非常多,為此它實(shí)現(xiàn)了一整套自己的mutex機(jī)制,ReaderWriterMutex是其中一種特殊的mutex。與普通的mutex相比,它主要提供了如下以下差異接口:

void ExclusiveLock(Thread* self) ACQUIRE();
void ExclusiveUnlock(Thread* self) RELEASE();
bool ExclusiveLockWithTimeout(Thread* self, int64_t ms, int32_t ns)
         EXCLUSIVE_TRYLOCK_FUNCTION(true);
void SharedLock(Thread* self) ACQUIRE_SHARED() ALWAYS_INLINE;
void SharedUnlock(Thread* self) RELEASE_SHARED() ALWAYS_INLINE;

Exclusive和Shared分別代表Write和Read權(quán)限,讀寫(xiě)鎖允許多個(gè)對(duì)象共享Read鎖而只能有一個(gè)對(duì)象擁有Write鎖。此外,讀寫(xiě)鎖還有Free、Exclusive和Shared三種狀態(tài)。

文章內(nèi)容來(lái)自——林學(xué)森,深入理解Android內(nèi)核設(shè)計(jì)思想,北京:人民郵電出版社,2017.7

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容