6

COM オブジェクトで多くのメソッドを呼び出すメイン STA スレッドと、同じオブジェクトでも多くの作業を行うセカンダリ STA スレッドがあります。メイン スレッドとセカンダリ スレッドを並行して動作させたい (つまり、メイン スレッドとセカンダリ スレッドからインターレース出力を期待している)。時々メイン スレッドでメッセージを送信する必要があることはわかっています。C++ で Get/Translate/DispatchMessage を呼び出すと、うまくいきます。

しかし、C#で同じ戦略を機能させるのに問題があります。最初に、メイン スレッドで CurrentThread.Join() を使用して、2 番目のスレッドに制御を渡しました。うまくいきませんでした。次に、Application.DoEvents() に目を向けました。2 番目のスレッドを実行したいときはいつでも、メイン スレッドで呼び出しました。その結果、2 番目のスレッドはすぐにコントロールを取得し、手放しません。2 番目のスレッドがすべて完了するまで、メイン スレッドは続行できません。

Application.DoEvents() がすべての待機中のイベントを処理するというドキュメントを読みましたが、GetMessage() は 1 つのメッセージのみを取得します。

どうするのが正しいのでしょうか?Get/Translate/DispatchMessage に相当する C# はありますか?

ありがとう

更新: 2 番目のスレッドの実行速度が速すぎて、大量の COM 呼び出しメッセージをメイン STA スレッドに送信しています。2番目のスレッドに遅延を追加して、速度を落としました。現在、2 つのスレッドが基本的に並行して実行されています。しかし、GetMessage/TranslateMessage/DispatchMessage に相当する C# があるかどうかを知りたいです。

4

2 に答える 2

8

元の C++ コードが STA 契約に違反しています。これは、オブジェクトのすべての呼び出しが 1 つのスレッドのみから行われるように、インターフェイス ポインターをあるスレッドから別のスレッドにマーシャリングする必要があることを示しています。これは、シングルスレッド COM サーバーの厳しい要件です。そうしないと、スレッドセーフではないコードでの複数のスレッドからの make 呼び出しに関連する典型的な問題が発生する危険があります。2 つの STA スレッドを使用しても、この要件から解放されるわけではありませ。オブジェクトは、それを作成したスレッドによってのみ所有されます。2 番目のスレッドは単なる別のスレッドであり、サーバーがマルチスレッドをサポートしていないため、そこからの呼び出しを安全に行うことはできません。

あなたはどうにかして C++ コードでそれを回避しました。それ以外の場合、COM はインプロセス COM サーバーで STA コントラクトを強制することはできず、アウトプロセス サーバーでのみ強制されます。その場合、コントラクトに違反すると RPC_E_WRONG_THREAD が生成されます。

とにかく、C#プログラムでこれを回避することはもうありません。CLR は、インターフェイス ポインターを自動的にマーシャリングします。2 番目のスレッドで行う呼び出しは、オブジェクトを所有する STA スレッドにマーシャリングされます。まだインターリーブがありますが、2 番目のスレッドの呼び出しは、最初のスレッドがアイドル状態になり、メッセージ ループに再び入るときにのみ配信できます。これに対する回避策はありません。インターフェイス ポインターの CLR 処理は厳密に規則に従っています。

これは、私が想像するコードに多くの結果をもたらします。最大の結果は、2番目のスレッドが実際には何も達成しなくなったことです。同時実行性はなく、オブジェクトへのすべての呼び出しは厳密にシリアル化されます。そしてスレッドセーフ。おそらく、1 つのスレッドからすべての呼び出しを行う方がよいでしょう。そうすれば、デッドロックのリスクを回避する必要がなくなります。おまけとして、適切なメッセージポンピングの重要性を大幅に軽減します。2 番目のスレッドが他の重要な作業を行う場合は、シングルスレッド コードの COM サポートを利用すると便利です。

于 2011-07-21T05:36:12.013 に答える
4

.Net での Get/Translate/Dispatch に関する限り、ヘルパー スレッドでApplication.RunまたはDispatcher.Run() (winforms を使用しているか wpf を使用しているかによって異なります)を呼び出すことができるはずです。これにより、Get/Trans/Dispatch を呼び出すスレッドでメッセージ ループが発生します。その考えが嫌いなら、Win32 呼び出しを P/Invoke することができます。

.Net はhans の回答に従ってほとんどすべてを機能させますが、実際には、基になる DispatchMessage() に長い時間がかかるように見えるため、COM オブジェクトからのメッセージによって UI スレッドが途切れる可能性があることがわかりました (確かに予想よりも長く、または説明できませんでした)。ソリューションを変更して、ヘルパー スレッドで COM オブジェクトを作成し、UI スレッドから明示的に COM オブジェクトへの呼び出しをマーシャリングしました。

于 2011-07-21T06:07:20.683 に答える