Binder系列10 Binder執行緒池管理

2021-10-09 10:26:01 字數 4260 閱讀 2442

在系列1中我們知道 binder 通訊,歸根結底是位於不同程序中的執行緒之間的通訊.假如程序 s 是 server 端,提供 binder 實體,執行緒 t1 從 client 程序 c 中通過 binder 的引用向程序 s 傳送請求。s 為了處理這個請求需要啟動執行緒 t2,而此時執行緒 t1 處於接收返回資料的等待狀態。t2 處理完請求就會將處理結果返回給 t1,t1 被喚醒得到處理結果.這個是 binder 通訊的基本過程.

對於 server 程序 s 來說,可能會有許多 client 同時向其發起請求,為了提高效率往往開闢執行緒池併發處理收到的請求.怎樣使用執行緒池來實現併發處理呢?這和具體的 ipc 機制有關.對於 binder 機制來說,它是怎麼管理執行緒池的呢?一種簡單的做法是,不管三七二十一,先建立一堆執行緒,每個執行緒都用 binder_write_read 命令讀 binder。這些執行緒會阻塞在驅動為該 binder 設定的等待佇列上,一旦有來自 client 的資料,驅動會從等待佇列中,喚醒乙個執行緒來處理。這樣做簡單直觀,省去了執行緒池,但一開始就建立一堆執行緒有點浪費資源。於是 binder 協議引入了專門的命令或訊息幫助 binder 驅動管理執行緒池,包括:

首先要管理執行緒池就要知道池子有多大,應用程式通過 binder_set_max_threads 告訴驅動,最多可以建立幾個執行緒。以後每個執行緒在建立,進入主迴圈,退出主迴圈時,都要分別使用 bc_register_loop,bc_enter_loop,bc_exit_loop 告知驅動,以便驅動標記當前執行緒池中各個執行緒的狀態。每當驅動接收完資料報,並且把資料報返回給讀 binder 執行緒的使用者空間時,都要檢查一下,執行緒池中是不是已經沒有閒置執行緒了 .如果是,並且執行緒總數還沒有達到執行緒池設定的最大執行緒數,就會在當前讀出的資料報後面再追加一條 br_spawn_looper 命令,告訴 server 端,執行緒即將不夠用了,請再啟動乙個新執行緒,否則下乙個請求可能不能及時響應。新執行緒一啟動,又會通過 bc_***_loop 等一系列命令告知驅動更新執行緒的狀態.這樣確保了只要執行緒池的執行緒數量沒有耗盡,總是會有空閒的執行緒在等待佇列中隨時待命,及時處理請求,這個就是 binder 機制執行緒池管理的基本流程,下面比照**詳細分析.

我們知道在 mediaplayerservice 啟動的 main 函式中,最後二行**是關於 binder 執行緒池的啟動的,我們來看**:

int

main

(int argc __unused,

char

**ar** __unused)

void processstate::

startthreadpool()

}

啟動 binder 執行緒池後,則設定 mthreadpoolstarted 為 true.通過變數 mthreadpoolstarted 來保證每個應用程序只允許啟動乙個 binder 執行緒池,且本次建立的是 binder 主線程,以變數 ismain 為 true 為標誌. 其餘 binder 執行緒池中的執行緒都是由 binder 驅動通過傳送 br_spawn_looper 命令來通知應用程序建立的.

void processstate::

spawnpooledthread

(bool ismain)

}

string8 processstate::

makebinderthreadname()

獲取 binder 執行緒名稱,格式為 binder:pid_s(其中pid為程序號;s為序列號,每次累加1).每個程序中的 mthreadpoolseq 是從1開始,依次遞增; 只有通過 spawnpooledthread 方法來建立的執行緒才符合這個格式,對於直接將當前執行緒通過 jointhreadpool 加入執行緒池的執行緒名則不符合這個命名規則.

class

poolthread

:public thread

protected

:virtual

bool

threadloop()

const

bool mismain;

};

該 poolthread 類繼承 thread 類,呼叫它的 run() 方法最終會呼叫到 poolthread 的 threadloop() 方法.

void ipcthreadstate::

jointhreadpool

(bool ismain)

}while

(result !=

-econnrefused && result !=

-ebadf);.

....

... mout.

writeint32

(bc_exit_looper)

;//通知binder驅動執行緒退出

talkwithdriver

(false);

//false表示不讀binder驅動資料,只寫

}

jointhreadpool 的實際工作就是迴圈呼叫 getandexecutecommand 函式,這個 getandexecutecommand 函式的主要作用就是從 binder 驅動讀取資料並處理,主線程不會退出,非主線程超時的時候會退出,退出的時候需要向 binder 驅動傳送命令碼 bc_exit_looper 告知驅動.

void ipcthreadstate::

processpendingderefs()

mpendingweakderefs.

clear()

;}numpending = mpendingstrongderefs.

size()

;if(numpending >0)

mpendingstrongderefs.

clear()

;}}}

status_t ipcthreadstate::

getandexecutecommand()

return result;

}

getandexecutecommand 不斷呼叫 talkwithdriver 讀取從 binder 驅動傳輸過來的資料,然後呼叫 executecommand 函式解析並處理,關於 talkwithdriver 函式與 executecommand 函式我們之前已經講過,在此不再贅述.下面專門單獨分析下 br_spawn_looper 命令的處理.

status_t ipcthreadstate::

executecommand

(int32_t cmd)..

....

..return result;

}

這個就是 binder 驅動通過傳送命令 br_spawn_looper 主動要求使用者程序建立的非主線程,同樣是呼叫 spawnpooledthread 函式用來建立執行緒,不同的是引數為 false 表示非主線程.

我們知道我們可以通過 binder_set_max_threads 命令來告知 binder 驅動每個程序可以建立的最大的 binder 執行緒的個數,一般來說這個值預設值為15,當然我們可以自己設定.但是要注意的是,這個不是說 binder 執行緒池中最大的執行緒數目就是15個了,這個值僅僅是對binder 驅動來說的,它只統計使用 bc_register_looper 命令建立的執行緒個數,如果達到就不在建立了;舉個我們討論的 mediaplayerservice 的例子:

int

main

(int argc __unused,

char

**ar** __unused)

這個程序的執行緒池中最多可以有幾個 binder 執行緒呢?我們來計算下,因為在 processstate 初始化的過程中會呼叫 open_driver 函式,在這個函式中設定了最大執行緒數為15,所以這15個執行緒是保底的,另外 main 函式的最後二行**的 startthreadpool,我們知道是新啟動了乙個執行緒,並設定為主執行緒,是通過 bc_enter_loop 來建立的,不計入15個之列,所以又可以建立乙個執行緒;同時看最後一行** ipcthreadstate::self()->jointhreadpool() 是把當前的執行緒新增到執行緒池中,jointhreadpool 預設引數為 true,所以也是主線程,也是通過 bc_enter_loop 命令來建立的,所以又可以建立乙個執行緒了,所以這個media服務程序最多可以有17個執行緒在工作,大家要理解.

從以上對 binder 執行緒池數量的分析我們已經知道了 binder 執行緒可以有三類,總結如下:

Binder系列10 總結

從android driver層 binder還可以理解為一種虛擬的物理裝置,它的裝置驅動是 dev binder 從android native層 binder是建立service manager以及bpbinder bbinder模型,搭建與binder驅動的橋梁 從android framew...

Binder面試系列之三

1.1 簡介 記憶體 現代計算機都有兩種以上的執行模式 普通模式 特權模式 linux系統只有兩層 使用者空間 linux系統在高優先順序模式中執行系統核心 以及與硬體密切相關的 低優先順序執行應用程式與硬體無關部分。應用程式不能直接操控硬體或者呼叫核心函式,需借助一系列介面函式申請讓系統呼叫相關 ...

Entity Framework1 0系列文章

需要說明的是,以下文章是基於entity framework1.0的,環境是vs2008 sp1,部分內容與最新的entity framework4.0及以上版本是有區別的,畢竟entity framework4.x有巨大的改進.entity framework 學習初級篇1 ef基本概況 enti...