GC Threading Problem on Managed DirectX

Managed DirectX での早期導入にも期待しておきます.C++/CLI から SafeHandles を使うときはまたちょこっと印象変わるかもしれませんね.

以前,菊池さんところ経由で SafeHandle について書いたときに Managed DirectX に SafeHandles が使えないかという話が出ていましたが,後でふと気になったことがあって試してみたところ,スレッド周りで問題が起きそうなことを確認しました.
DirectX Graphics は Win32 Native Thread と密に結合しています*1.試しに手元の DirectX 9.0c Debug Runtiem 環境で以下のようなコードを実行してみました.

  1. 通常通りデバイスを作成
  2. 別スレッドを作って,そのスレッドでデバイスを解放

すると,デバッグメッセージには次のように表示されました.

Direct3D9: (ERROR) :Final Release for a device can only be called from the thread that the device was created from.

このことから,Managed DirectX で SafeHandle を使ったとしても解放作業自体はせいぜい ReliabilityContract(Consistency.MayCorruptProcess, Cer.MayFail) ということになるかと思います.
このようにスレッドに密結合するアンマネージリソースを .NET に対応させる場合,2つの点で厄介と考えられます.

  1. CLR Hosting API は,ソフトスレッドとハードスレッドの対応をカスタマイズすることを許している
  2. Finalizer は専用のスレッドから呼ばれる

まあ現実には(1)が問題になる局面ではそもそも WinForms からして問題が出るかもしれません.また,IDisposable を実装しているということのみからスレッド依存性を知ることは無理でしょうから,単純に IDisposable.Dispose を呼べば解決,とは言えない例のひとつでもあるでしょう.

*1:Win32 ウィンドウのサブクラス化を行うことが影響しているのかもしれません