線程模型

線程模型

標記爲 oneway 的方法不會阻塞。對於未標記爲 oneway 的方法,在服務器完成執行任務或調用同步回調(以先發生者爲準)之前,客戶端的方法調用將一直處於阻塞狀態。服務器方法實現最多可以調用一個同步回調;多出的回調調用會被捨棄並記錄爲錯誤。如果方法應通過回調返回值,但未調用其回調,系統會將這種情況記錄爲錯誤,並作爲傳輸錯誤報告給客戶端。

直通模式下的線程

在直通模式下,大多數調用都是同步的。不過,爲確保 oneway 調用不會阻塞客戶端這一預期行爲,系統會分別爲每個進程創建線程。要了解詳情,請參閱 HIDL 概覽

綁定式 HAL 中的線程

爲了處理傳入的 RPC 調用(包括從 HAL 到 HAL 用戶的異步回調)和終止通知,系統會爲使用 HIDL 的每個進程關聯一個線程池。如果單個進程實現了多個 HIDL 接口和/或終止通知處理程序,則所有這些接口和/或處理程序會共享其線程池。當進程接收從客戶端傳入的方法調用時,它會從線程池中選擇一個空閒線程,並在該線程上執行調用。如果沒有空閒的線程,它將會阻塞,直到有可用線程爲止。

如果服務器只有一個線程,則傳入服務器的調用將按順序完成。具有多個線程的服務器可以不按順序完成調用,即使客戶端只有一個線程也是如此。由於 oneway 調用不會阻塞客戶端,因此具有多個線程的服務器可以同時或不按順序處理多個 oneway 調用,而且 oneway 調用可以與後續的阻塞調用並行處理。

服務器線程模型

(直通模式除外)HIDL 接口的服務器實現位於不同於客戶端的進程中,並且需要一個或多個線程等待傳入的方法調用。這些線程構成服務器的線程池;服務器可以決定它希望在其線程池中運行多少線程,並且可以利用一個線程的線程池規模,以便按順序處理其接口上的所有調用。如果服務器的線程池中有多個線程,則服務器可以在其任何接口上接收同時傳入的調用(在 C++ 中,這意味着必須謹慎鎖定共享數據)。

傳入同一接口的單向調用會按順序進行處理。如果多線程客戶端在接口 IFoo 上調用 method1 和 method2,並在接口 IBar 上調用 method3,則 method1 和 method2 將始終按順序運行,但 method3 可以與 method1 和 method2 並行運行。

單一客戶端執行線程可能會通過以下兩種方式在具有多個線程的服務器上引發並行運行:

  • oneway 調用不會阻塞。如果執行 oneway 調用,然後調用非 oneway,則服務器可以同時執行 oneway 調用和非 oneway 調用。
  • 當系統從服務器調用回調時,通過同步回調傳回數據的服務器方法可以立即解除對客戶端的阻塞。
    對於第二種方式,在調用回調之後執行的服務器函數中的任何代碼都可以並行運行,同時服務器會處理來自客戶端的後續調用。這包括服務器函數以及在函數結束時執行的自動析構函數中的代碼。如果服務器的線程池中有多個線程,則即使調用僅從一個單一客戶端線程傳入,也會出現並行處理問題。(如果一個進程提供的任意 HAL 需要多個線程,則所有 HAL 都將具有多個線程,因爲線程池是按進程共享的。)

當服務器調用所提供的回調時,transport 可以立即調用客戶端上已實現的回調,並解除對客戶端的阻塞。客戶端會繼續與服務器實現在調用回調之後所執行的任何任務(可能包括正在運行的析構函數)並行運行。回調後,服務器函數中的代碼不會再阻塞客戶端(但前提是服務器線程池中有足夠多的線程來處理傳入的調用),但可以與來自客戶端的未來調用並行執行(除非服務器線程池中只有一個線程)。

除了同步回調外,來自單線程客戶端的 oneway 調用也可以由線程池中具有多個線程的服務器並行處理,但前提是在不同的接口上執行這些 oneway 調用。同一接口上的 oneway 調用始終按順序處理。

注意:我們強烈建議服務器函數在調用回調函數後立即返回。

例如(在 C++ 中):

Return<void> someMethod(someMethod_cb _cb) {
    // Do some processing, then call callback with return data
    hidl_vec<uint32_t> vec = ...
    _cb(vec);
    // At this point, the client's callback will be called,
    // and the client will resume execution.
    ...
    return Void(); // is basically a no-op
};

客戶端線程模型

非阻塞調用(帶有 oneway 關鍵字標記的函數)與阻塞調用(未指定 oneway 關鍵字的函數)的客戶端線程模型有所不同。

阻塞調用

對於阻塞調用來說,除非發生以下情況之一,否則客戶端將一直處於阻塞狀態:

  • 出現傳輸錯誤;Return 對象包含可通過 Return::isOk() 檢索的錯誤狀態。
  • 服務器實現調用回調(如果有)。
  • 服務器實現返回值(如果沒有回調參數)。

如果成功的話,客戶端以參數形式傳遞的回調函數始終會被服務器在函數本身返回之前調用。回調是在進行函數調用的同一線程上執行,所以在函數調用期間,實現人員必須謹慎地持有鎖(並儘可能徹底避免持有鎖)。不含 generates 語句或 oneway 關鍵字的函數仍處於阻塞狀態;在服務器返回 Return 對象之前,客戶端將一直處於阻塞狀態。

單向調用

如果某個函數標記有 oneway,則客戶端會立即返回,而不會等待服務器完成其函數調用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章