C++とRustを同じプロジェクトで使いたい。しかし、スレッドモデルの違いが壁です。Antithesis社はこの課題を解決しました。そこで今回は、同社の統合手法を解説します。
Antithesis社の技術的背景
Antithesisはテスト自動化の企業です。具体的には、ファジーテストツールを開発しています。このツールはシングルスレッドのC++で書かれています。しかし、新機能はRustで開発する方針になりました。つまり、同期C++と非同期Rustの橋渡しが必要でした。特にC++の参照カウントがスレッド安全でない点が問題です。また、C++のメソッドはメインスレッドでのみ安全に動作します。そのため、単純な統合は不可能でした。
FFI構築とスレッド安全性の工夫
cxxクレートでFFIを構築しました。また、非同期チャネルでデータ交換を実現しています。さらに、いくつかの独自パターンを導入しました。まずCppOwner構造体です。これでC++オブジェクトを安全に共有します。次にSendWrapperです。つまり、非Sendな型をスレッド境界で使えるようにします。
特に重要なのがDropQueueです。具体的には、C++オブジェクトをメインスレッドで安全に破棄します。また、MainThreadTokenも導入しました。これはメインスレッド実行を型で保証します。しかも、ランタイムコストはゼロです。そのため、安全性とパフォーマンスを両立できます。
C++側の命名規約と教訓
C++側ではSYNCとUNSYNCのマーカーを使います。つまり、スレッド安全性を名前で示すのです。そのため、コードレビューが容易になります。また、Rustの型システムが安全性を強制してくれます。なぜなら、開発者の規律に依存しないからです。
この事例から重要な教訓が得られます。まず、慎重に設計すれば統合は可能という点です。さらに、型による安全性の保証が効果的です。したがって、C++資産を持つチームには参考になります。だからこそ、言語間連携を検討する開発者は必見の事例です。