2010-12-12 25 views
5

私はこの単純なコードを持っています。 プロセスエクスプローラとVSデバッガのどちらかで、スレッドが作成され、その状態が「実行中」であることがわかります。スレッドの問題

メインスレッドのアパートはSTAです。私は内部スレッドでSTAとMTAの両方を試しました。

最後にRun()メソッドに追加すると、invokerThread.Join();のスレッドが実行されます。しかしもう一度それは本当に助けにはならない。

私には何が欠けていますか?

編集:ここでは、コードホスティングに関するいくつかの詳細は、 -

Run()方法はまた、COM相互運用機能を使用する理由は、であるため、他のすべての構成要素である(実行アセンブリを管理しているプロセスからCOM相互運用機能を介して呼び出されますシステムはネイティブです)。

RunOnBackground()のメソッドは、トレースの後にいくつかのコードを含み、一般にその実行は別のプロセスを開始し、その終了を待つことを含めて、10〜20秒間続きます。また、トレースにいくつかのデバッグ情報を書き込むコードのいくつかの領域があります。コードをデバッグしている間に、​​の後にRun()が正常に実行されます。RunOnBackground()メソッド内のブレークポイントは停止しませんが、invokerThreadの状態は「実行中」です。

私は、デバッガがJoin()RunOnBackground()に行くRun()メソッドの最後にinvokerThread.Join()を追加します。

+0

メッセージボックスをワーカースレッド内に表示しないでください。トレースを使用するように変更 –

+0

コードを更新しました。まだ動作しません。私がマーティンに書いた回答を見てください。 – Aaron

+0

あなたは言った: "残念なことに、このコードを(第三者のプロセスから)実行するとスレッドは実際には動かない"どのように正確に "このコードを実行していますか"? –

答えて

3

RunOnBackground()が実際にとは何かに関する重要な情報がありません。これは、ワーカースレッド上でアパートメントスレッドCOMオブジェクトを使用すると、何が起きるかに適しています。 COMは、ワーカースレッドからそのオブジェクトが作成されたSTAスレッドへのそのようなオブジェクトのメソッド呼び出しを自動的にマーシャリングします。

これは、STAスレッドがSTAスレッド要件を満たしている場合にのみ有効です。メッセージループを励起し、ブロックすることはできません。これらのルールを破ると、デッドロックが発生する可能性が非常に高くなります.STAスレッドがマーシャルされたコールをディスパッチするまでワーカースレッドコールは完了できません。これが起こっていることの確かな兆候は、Thread.Join()が問題を解決しているのを見ることです。 STAスレッドで呼び出されたときにCLR内部でメッセージループをポンプします。

これを診断するには、そのワーカースレッドがブロックしているものを確認するためにDebug + Windows + Threadsが必要です。私の推測が正しいとすれば、マーシャリングされた呼び出しが完了するのを待って、COM配管コードの真ん中に埋め込まれます。アンマネージドコードのデバッグを有効にし、Microsoft Symbol Serverをセットアップして、配管コードのデバッグシンボルを取得し、信頼できるスタックトレースを取得できるようにすることで、これを確認できます。

これを修正するのは難しいでしょう。マルチスレッドをサポートしていないことを明示的に宣言している場合、スイッチを魔法のように反転してコードをスレッド上で実行させることはできません。そのメソッドを呼び出す同じスレッド上にCOMオブジェクトのインスタンスを作成することが不可欠です。そのスレッドはSTAスレッドでなければなりません。アプローチについてはsample codeにチェックしてください。 COMオブジェクトの作成を制御しないと、スタックしません。

+0

ハンス、簡単な答えをありがとう。あなたは "...ワーカースレッドがブロックしているものを見てください"と書いています。実際にはデバッグ中にStart()の後にワーカースレッドの状態が「実行中」に変更されています。 RunOnBackground()メソッドは、他のメソッドを呼び出して、別のプロセスを開始して終了するまで待機しますが、RunOnBackground()メソッド内のすべてをコメントアウトし、シンプルなTrace.Writeいくつかの代入(var x = 1;のような)。 – Aaron

0

私は何かばかげたと言うかもしれませんが、ここで私が見たのはMSDN Threadsです。

最後の例のセクションを見てください。

この例の出力は面白いです。メインスレッドがスリープ(0)またはThread.Join()を実行したときにのみ、作成され起動されたスレッドが実行を開始することがわかります。

あなたには何が起こっているようですね。

あなたのメインスレッドでスリープ(0)を試して、実際にあなたのスレッドを起動することがあります。

もう1つの回避策は、BackGroundWorkerを使用することです。

名前の通り、バックグラウンドで動作し、使いやすいです。それはあなたにとって大変役に立つかもしれません。

+0

Thread.Sleep()で試しました。助けにならない。 BackgroundWorkerも起動しません。 – Aaron