Android所擁有的IPC
Android系統中有大量IPC(進程間通信)的場景,比如我們想要
- 創建一個新的進程,需要通過Socket這種IPC方式去讓Zygote Fork新進程;
- 如果我們要殺掉一個進程,需要通過信號這種IPC方式去將SIGNAL_KILL信號傳遞到系統內核;
- 如果我們想要喚醒主線程處于休眠中的Looper,需要管道這種IPC方式來喚醒;
- 我們想要在應用開發中使用AIDL,廣播或者Messager等方式來進行跨進程通信,其實底層都是使用了Binder這種IPC方式。
那么,Android到底有多少種進程間通信的方式呢?什么樣的場景要選擇什么樣的通信方式呢?這些IPC通信方式怎么使用呢?這些IPC通信的底層原理又是什么呢?
可以看到,Android所擁有的IPC總共有這些:
- 基于Unix系統的IPC的管道,FIFO,信號
- 基于SystemV和Posix系統的IPC的消息隊列,信號量,共享內存
- 基于Socket的IPC
- Linux的內存映射函數mmap()
- Linux 2.6.22版本后才有的eventfd
- Android系統獨有的Binder和匿名共享內存Ashmen
管道
信號(signal)
消息隊列
信號量(semaphore)
上面提到的IPC的方式都是在內核空間中開辟內存來存儲數據,寫數據時,需要將數據從用戶空間拷貝到內核空間,讀數據時,需要從內核空間拷貝到自己的用戶空間,
共享內存就只需要一次拷貝,而且共享內存不是在內核開辟空間,所以可以傳輸的數據量大。
共享內存(share memory)
套接字(Socket)
Android跨進程通信-mmap函數
Android進程間通信-eventfd
8 Linux的幾種跨進程通信的方式的比較
8.1 效率比較
類型 | 無連接 | 可靠 流控制 | 優先級 | |
---|---|---|---|---|
匿名PIPE | N | Y | Y | N |
命名PIPE(FIFO) | N | Y | Y | N |
信號量 | N | Y | Y | Y |
消息隊列 | N | Y | Y | Y |
共享內存 | N | Y | Y | Y |
UNIX流SOCKET | N | Y | Y | N |
UNIX數據包SOCKET | Y | Y | N | N |
PS:無連接是指無需調用某種行動是OPEN,就有發送消息的能力流控制,如果系統資源短缺或者不能接受更多的消息,則發送進程能進進行流量控制
8.2 優缺點比較
- 匿名管道(pipe):速度慢,容量有限,只有父子進程能通訊
- 有名管道(FIFO): 任務進程都能通訊,但速度慢
- 消息隊列(message queue):容量受到系統限制,且要注意第一次讀的時候,要考慮上一次沒有讀完數據問題。
- 信號量:不能傳遞復雜消息,只能用來同步
- 共享內存區:能夠容易控制容量,速度快,但要保持同步,比如一個進程在寫的時候,另一個進程要注意讀寫的問題。相當于線程中的線程安全,當然,共享內存區同樣可以做線程間通訊,不過沒有這個必要,線程間本來就已經共享了同一進程內的一塊內存
8.3 使用場景
- 如果用戶傳遞的信息較少或是需要通過信號來出發某些行為,上面提到的軟中斷信號機制不失為一種簡潔有效的一種進程間通信方式。但若是進程間要求傳遞的信息量比較大或者進程間存在交換數據的要求,那就需要考慮別的通信方式。
- 匿名管道簡單方便,但局限于單向通信的工作方式,并且只能創建它的進程及其子孫進程之間實現管道的共享。
- 有名管道雖然可以提供給任意關系的進程使用,但是由于其長期存在于系統之中,使用不當容易出錯。所以不建議初級開發者使用。
- 消息緩存可以不再局限于父子進程,而允許任意進程間通過共享消息隊列來實現進程間通信,并由系統調用函數來實現消息發送和接受方之間的同步,從而使得用戶在使用消息緩沖進行通信時不再需要考慮同步問題,使用方便,但是信息的復制需要額外的消耗CPU的時間,不適宜信息量大或操作頻繁的場合。
- 共享內存針對消息緩存的缺點而改進,利用了內存緩存區直接交換信息,無需復制,快捷、信息量大的是其優點。但是共享內存的通信方式是通過將共享內存緩存直接附加到進程的虛擬地址空間中來實現的。因此這些進程之間的讀寫操作的同步問題操作系統無法實現。必須由各進程利用其它同步工具解決。另外, 由于內存實體存在于計算機系統中,所以只能由處于同一個計算機系統中的其它進程共享,不方便網絡通信。
- 共享內存塊提供了在任意數量的進程之間進行高效雙向通信的機制。每個使用者都可以讀取寫入數據,但是所有程序之間必須達成并遵守一定的協議,以防止諸如在讀取信息之前覆寫內存空間等競爭狀態的出現。不行的是,Linux無法嚴格保證提供對共享內存塊的獨占訪問,同時,多個使用共享內存塊的進程之間必須協調使用同一個鍵值。