本節將協助您瞭解如何使用新的 C++ FIDL 繫結。詳情請見 開始使用 從頭開始建構及編寫簡單的用戶端或伺服器查看主題 ,提供相關指南和建議,協助您瞭解如何有效使用繫結。 請參閱術語,瞭解所發名稱和概念 並快速說明如何做出正確選擇。
大致上,C++ 繫結由以下元素組成:
- 資料: 網域物件 ( 產生的 FIDL 結構,例如結構體、資料表、...)
- 行為:供用戶端/伺服器 API 透過 通訊協定、接收事件...
自然和電線域的物體
這些繫結支援兩種網域物件:natural 類型和 線類型:
- 自然類型是針對人體工學最佳化的高層級網域物件。
- 這些型別會使用智慧指標負責子項。
- 這類函式會使用慣用的 C++ 類型,例如
std::vector
、std::optional
和std::string
。 - 如果有名為
fuchsia.my.lib
的 FIDL 程式庫,系統就會產生類型 在fuchsia_my_lib
命名空間中。
- 線類型已針對效能最佳化,並就地解碼。
- 這些是特殊的 C++ 標準版面配置類型,其記憶體佈局 符合 FIDL 線格式。
- 行外子項是進入獨立緩衝區的無從指標。 請參閱接線網域物件的記憶體擁有權。
- 如果有名為
fuchsia.my.lib
的 FIDL 程式庫,系統就會產生類型 在fuchsia_my_lib::wire
命名空間中。
啟動專案時,預設選擇自然類型,因為比較容易使用 而且效能合理最佳化時只轉做電線類型 或需要精確控制記憶體時 分配速度。由於線路類型包含不安全的檢視畫面,不當使用 以免使用釋放後記憶體 以及其他記憶體安全錯誤
開始使用
- 使用自然來源和線路域物體
- 寫入伺服器
- 寫入用戶端 (非同步或同步)
主題
術語
用戶端和伺服器的Wire
與Wire
相比
如果用戶端/伺服器 API 名稱中出現 Wire
前置字串,代表 API 已啟用
只接受電線類型。否則,API 通常可以接受
或預設為自然型別例如:fidl::Client
支援透過自然或有線方式撥打電話,
fidl::WireClient
提供限制更嚴格的介面,只接受有線
。
「fidl::Server
」會接收自然類型的要求,但可能會傳送以下回覆:
自然或線路類型另一方面,fidl::WireServer
獲得
轉交連線類型,並專門傳送電線類型回覆。
為了在不使用功能的情況下同時支援傳訊端的線路和自然類型
過載不明確的問題,電線介面是放在 .wire()
存取子底下。
以 fidl::Client<MyProtocol> client;
為例
client->SomeMethod(natural_type);
會透過自然類型提出要求
client.wire()->SomeMethod(wire_type);
以使用線路類型提出要求。
建議
使用不含 Wire
前置字串的用戶端/伺服器 API。只有在必要時
確保在編譯期間只使用線型,其中一種可能定義了函式
使用 Wire
對應工具的簽章,例如:fidl::WireClient
。其中之一
這也取決於繫結的電線部分,具體方式取決於
fuchsia.my.lib_cpp_wire
目標而非 fuchsia.my.lib_cpp
GN 目標。
客戶的Sync
對比 sync
同步或「同步」適用於包含回應的 FIDL 呼叫
表示通話處於封鎖狀態:發出這類呼叫的執行緒不會
,直到回應傳回為止。例如:
fidl::WireSyncClient
是所有雙向呼叫都同步的用戶端。
同樣地,fidl::WireClient
的 .sync()
存取子會傳回
發出同步呼叫的介面。
單向呼叫沒有回應,因此同步性的概念 不適用於它們
建議
如果程式碼是獨立程式,只會取用來自其他 Google 服務的能力 元件,決定其業務需求所需的並行程度:
如果沒有管理大量並行作業,您可以使用 方便閱讀直行邏輯。舉例來說 短執行的指令列工具可能會使用
fidl::SyncClient
。如果您的程式碼管理大量並行作業,通常就能存取 非同步調度工具 (
async_dispatcher_t*
)。選擇合適的解決方案時 在這種情況下,最好使用 非同步版本例如,使用fidl::WireClient
但不參加 透過.sync()
透過fidl::WireSyncClient
或.sync()
送達。尤其是 如果調度工具為單個,則不要在調度器執行緒上同步呼叫 執行緒,以避免死結
如果您的程式碼是服務,也就是提供 應使用非同步調度器和非同步用戶端 可支援多位消費者所需的並行
如果您的程式碼是其他應用程式使用的程式庫, 再三考慮是否應該公開同步或 配合使用者需求調整非同步介面舉例來說 以及提供同步介面和 更加難以使用 實作非同步調度工具
以上是一般建議,不同非同步執行階段 提供更具體的建議
客戶的Shared
對比 shared
當用戶端類型為「共用」時物件可能會在容器上繫結至
任意執行緒查看執行緒中的 SharedClient
指南。有一個不含「分享」的對應項目,例如 Client
。
必須在調度工具執行緒上繫結和刪除。類似關係
介於 WireClient
和 WireSharedClient
之間。
建議
選擇 Client
或 SharedClient
時,請改選
Client
,除非應用程式的執行緒或效能需求
應用程式需要透過多執行緒使用用戶端。詳情請參閱
執行緒指南,瞭解使用
SharedClient
。Client
的額外限制旨在
可以降低記憶體競爭,以及使用釋放後使用的記憶體。例如,您可以使用 Client
物件也會出現在相同的單一執行緒非同步調度工具上。
雙向通話的Then
對ThenExactlyOnce
當非同步呼叫具有回應時,有兩種方法可以指定 回呼以接收該呼叫的結果:
- 使用
.ThenExactlyOnce(...)
時,系統一律會明確呼叫回呼 然後傳送結果 - 使用
.Then(...)
時,系統會在用戶端時自動捨棄回呼,而且不會顯示通知 物件已被刪除,因此適用於物件導向程式碼。
「Then
」的動機
進行非同步雙向呼叫時,系統會傳送這次呼叫的結果 執行已經離開應用程式,讓您可以之後再返回應用程式 發出呼叫的原始範圍非同步調度器之後 叫用您在進行呼叫時指定的後續追蹤邏輯 (稱為 。物件一經刪除後就要容易使用 導致記憶體損毀:
// The following snippet shows an example of use-after-free
// occurring in asynchronous two-way calls.
void Foo(fidl::WireClient<MyProtocol>& client) {
bool call_ok;
client->SomeMethod().Then(
// The following lambda function represents the continuation.
[&call_ok] (fidl::WireUnownedResult<SomeMethod>& result) {
// `call_ok` has already gone out of scope.
// This would lead to memory corruption.
call_ok = result.ok();
});
}
當接續擷取時
this
指標,而說的參照物件也擁有用戶端。刪除
外部物件 (進而刪除用戶端) 會導致所有待處理物件
呼叫失敗。接續執行時,它擷取的 this
指標不會
的時間。
Then
和 ThenExactlyOnce
都會登錄雙向呼叫的接續作業。
不過,Then
的設計宗旨是減輕上述的損毀情況。
具體違規事項如下:
Then
會確保最多只會呼叫一次提供的接續作業,直到 用戶端就會遭到刪除。如果只有接續程序,應選擇Then
擷取生命週期與用戶端相同的物件 (例如:使用者物件) 客戶擁有)。刪除使用者物件會導致 回呼函式。使用釋放後不會有使用上的疑慮。另一方面,
ThenExactlyOnce
可保證呼叫接續 (僅執行一次)。如果用戶端物件遭到刪除,接續就會收到 取消錯誤。請務必確認所有參照的物件仍使用中 也就是持續執行時,可能是在 用戶端物件也會遭到刪除。請選用ThenExactlyOnce
, 連續呼叫只能呼叫一次,例如與fpromise
個完成者或 FIDL 伺服器完成程式,或在單元測試期間。
建議
原則上:
- 如果您的回呼類似
client_->Foo([this]
,請使用Then
(請注意,client_
是成員變數)。 - 如果你的回呼看起來像
client->Foo([completer]
,或client->Foo([]
,或client->Foo([&]
(常見於單元測試),- 回呼會擷取弱指標或強弱指標
- 使用
ThenExactlyOnce
。
請勿擷取不同生命週期的物件,只讓 物件會在接續執行時運作。
Zircon 管道運輸與驅動程式庫運送
FIDL 通訊協定與在 FIDL 定義,用來判斷可能經歷的資源種類 通訊協定,也可能影響系統為傳送和接收作業產生的 API 訊息。C++ 繫結支援兩種傳輸方式:
Zircon 管道傳輸是以端點類型表示
《fidl::ClientEnd<SomeProtocol>
》和《fidl::ServerEnd<SomeProtocol>
》。
驅動程式傳輸使用端點類型 fdf::ClientEnd<SomeProtocol>
和
fdf::ServerEnd<SomeProtocol>
。
競技場
Arenas 物件會管理記憶體緩衝區集區,並提供有效的分配作業。 這些都普遍用於傳輸領域物件,並連接電線用戶端和伺服器, 避免使用昂貴的複本
競技場不會用於自然領域物件和相關用戶端, 封裝了記憶體配置的詳細資料。
您可以使用 fidl::Arena
建立存線網域物件
體育場館請參閱「記憶體管理」。
透過驅動程式傳輸使用通訊協定時
網域物件,應使用 fdf::Arena
物件來分配緩衝區
需要將訊息編碼