5

私はこの単純なコードを持っています:

public void Run()
{
   var invokerThread = new Thread(new ThreadStart(RunOnBackground));
   invokerThread.Start();
}

private void RunOnBackground()
{
   Trace.WriteLine("hi");
   ...
}

残念ながら、このコードを(サードパーティのプロセスから)実行すると、スレッドは実際には実行されません。プロセスエクスプローラーとVSデバッガーのどちらでも、スレッドが作成され、その状態が「実行中」であることがわかります。

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

Run()最後にメソッドに追加するとinvokerThread.Join();、スレッドは実行されます。しかし、それでも実際には役に立ちません。

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

編集:ここにコードホスティングに関するいくつかの詳細情報があります-

Run()メソッドは、実行可能アセンブリも管理されているプロセスからCOM相互運用機能を介して呼び出されます(COM相互運用機能が使用される理由は、システム内の他のすべてのコンポーネントがネイティブであるためです)。

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

invokerThread.Join()メソッドの最後に追加するとRun()、デバッガーは。のRunOnBackground() に移動しJoin()ます。

4

2 に答える 2

3

RunOnBackground()が実際に何をするかについて、いくつかの重要な情報が欠落しています。それ以外の場合、これは、ワーカースレッドでアパートメントスレッドのCOMオブジェクトを使用したときに発生することとよく一致します。COMは、そのようなオブジェクトに対するメソッド呼び出しを、ワーカースレッドからそれが作成されたSTAスレッドに自動的にマーシャリングします。

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

これを診断するには、そのワーカースレッドが何をブロックしているかを確認するために、デバッグ+ウィンドウ+スレッドが必要です。私の推測が正しければ、マーシャリングされた呼び出しが完了するのを待って、COM配管コードの奥深くに埋め込まれます。これを確認するには、アンマネージコードのデバッグを有効にし、Microsoft Symbol Serverを設定して、配管コードのデバッグシンボルを取得し、信頼性の高いスタックトレースを取得する必要があります。

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

于 2010-12-13T15:45:37.787 に答える
0

ばかげたことを言うかもしれませんが、MSDNスレッドで見たものは次のとおりです。

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

この例の出力は興味深いものです。作成および開始されたスレッドは、メインスレッドがSleep(0)またはThread.Join()を実行した場合にのみ実行を開始することがわかります。

それはあなたに正確に起こっていることのようですよね?

たぶん、メインスレッドでSleep(0)を試して、実際に動作しているスレッドを起動してみてください。

別の回避策は、BackGroundWorkerを使用することです。

その名前が示すように、それは背景で動作し、本当に使いやすいです。それはあなたにとって非常に役立つかもしれません。

于 2010-12-13T00:17:10.930 に答える