StaTaskScheduler と STA スレッドのメッセージ ポンピング
Parallel チームの ParallelExtensionsExtras の StaTaskScheduler は、サードパーティが提供する従来の STA COM オブジェクトをホストするように設計されています。実装の説明には、MTA スレッドと STA スレッドをサポートし、WaitHandle.WaitAll などの基礎となる API の違いを処理すると記載されています。
ただし、STA スレッドでのデッドロックを防ぐために、StaTaskScheduler がメッセージを送信する待機 API (CoWaitForMultipleHandles など) を使用すると考えるのは誤りです。 TPL のブロック部分がメッセージを送出できない場合があり、デッドロックが発生します。
単純化したシナリオでは、インプロセス STA COM オブジェクト A がアウトプロセス オブジェクト B を呼び出し、B からのコールバックを取得することを期待しているときに問題が発生します。 BlockingCollection
解決策は、CoWaitForMultipleHandles を使用してメッセージを明示的にポンプするカスタム同期コンテキストを実装し、StaTaskScheduler によって開始されるすべての STA スレッドにインストールすることです。
MsgWaitForMultipleObjectsEx は、CoWaitForMultipleHandles よりもメッセージ ポンピングに適しています。カスタム同期コンテキストの Wait メソッドは、SynchronizationContext.WaitHelper へのフォワーダーとして実装することも、完全に機能するメッセージ ポンピング ループを含めることもできます。
次のコードは、メッセージ ポンピング ループを含むカスタム同期コンテキストの実装を示しています。
<code class="language-c#">// 核心循环 var msg = new NativeMethods.MSG(); while (true) { // 带有 MWMO_INPUTAVAILABLE 的 MsgWaitForMultipleObjectsEx 返回, // 即使消息队列中已经看到但未删除消息 nativeResult = NativeMethods.MsgWaitForMultipleObjectsEx( count, waitHandles, (uint)remainingTimeout, QS_MASK, NativeMethods.MWMO_INPUTAVAILABLE); if (IsNativeWaitSuccessful(count, nativeResult, out managedResult) || WaitHandle.WaitTimeout == managedResult) return managedResult; // 有消息,泵送并分派它 if (NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, NativeMethods.PM_REMOVE)) { NativeMethods.TranslateMessage(ref msg); NativeMethods.DispatchMessage(ref msg); } if (hasTimedOut()) return WaitHandle.WaitTimeout; }</code>
以上がブロッキング待機で StaTaskScheduler を使用する場合、STA スレッドでのデッドロックをどのように防ぐことができますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。