1

これを達成するための最良の方法は何ですか: メイン スレッド (スレッド A) は、他の 2 つのスレッド (スレッド B とスレッド C) を作成します。スレッド B と C は大量のディスク I/O を実行し、最終的に作成したリソースをスレッド A に渡して外部 DLL ファイルのメソッドを呼び出す必要があります。このメソッドでは、スレッドを作成したスレッドが正しく呼び出される必要があるため、スレッド A だけが呼び出すことができます。 .

これまでにスレッドを使用したのは Windows フォーム アプリケーションだけであり、invoke メソッドはまさに私が必要としていたものでした。このプログラムは Windows フォームを使用しないため、使用する Control.Invoke メソッドはありません。

私のテストでは、変数がスレッド A で作成された場合、スレッド B/C から問題なくアクセスして変更できることがわかりました。これは私には非常に間違っているようです。Winforms では、他のスレッドで作成されたものにアクセスしようとすると、エラーがスローされると確信していました。複数のスレッドから変更するのは安全ではないことはわかっていますが、安全なコーディングを保証するために、.NET がそれを完全に禁止することを本当に望んでいました。.NET はこれを行いますか?私は船に乗り遅れているだけですか?それとも WinForm アプリでのみ行うのでしょうか?

一見これを許可しているように見えるので、OS のようにフラグを作成し、スレッド A から監視して、変更があるかどうかを確認します。存在する場合は、メソッドを呼び出します。イベント ハンドラーは本質的にこれを行うわけではないので、メイン スレッドで呼び出されたイベントを何らかの方法で使用できますか?

4

4 に答える 4

4

通常、これは不要です。任意のスレッドから任意のオブジェクトのメソッドを呼び出すことができます。これは良いことです... UI コンポーネントと一部のレガシー COM コンポーネントは、特定のスレッドからアクセスする必要がある唯一の項目になる傾向があります。

通常、別のスレッドでメソッドを呼び出そうとする代わりに、同期 (例: lock(...) など) を使用して、データ自体へのアクセスを保護し、複数のスレッドから安全に作業できるようにします。スレッド。

は、よりきめ細かい保護を提供するため、パフォーマンスが向上します。Control.Invoke の使用は、Windows メッセージングを使用して実行する必要があるスレッドにフラグを立てるため、実際には非常にコストがかかります。

そうは言っても、これは実際には可能ですが、非常に困難です。「トリック」は、独自のスレッドでオブジェクトを作成し、そのオブジェクトにSynchronizationContextを提供させることができることです。その後、SynchronizationContext.Post または Send を使用して、そのコンテキスト内でメソッドを実行できます。

これを正しく行うのは非常に難しく、これを行う理由はほとんどないため、前述したように、ほとんどのシナリオではお勧めしません。

于 2010-03-18T15:28:38.970 に答える
0

私の視点から、あなたにとって最も簡単な方法は、BとCがアイテムをキューに入れる同期キューを操作することです。
次に、スレッドAはキューからデキューし、新しいものがキューに入れられるまで待機する可能性があります。このようなキューの簡単な例として、このMSDN記事
のDougからのコメントを見てください。デリゲートをキューに入れて、コードが正しいスレッドで実行されるようにすることもできます。

于 2010-03-18T15:48:24.050 に答える
0

まず、「Winforms」は、別のスレッドからデータにアクセスしようとしただけではエラーをスローしません。それは不可能です; どのスレッドが最初に何らかの変数を宣言したか、または何らかのデータを作成したかを知る方法はありません。Winformsで例外Control発生するのは、UI スレッド以外のスレッドから子孫でメソッドを呼び出そうとした場合です。これは非常に特殊なケースです。それを除けば、Winforms は他の .NET アプリケーションとまったく同じランタイム上で実行される単なるライブラリであり、スレッドの管理方法を特別に制御することはできません。

.NET Framework やその他のライブラリが安全なマルチスレッド コードを "保証" する方法はまったく考えられません。.NET 4 のコンカレント コレクション ライブラリ、不変データ型など、特定の概念は競合状態やその他の同時実行エラーを減らすのに役立ちますが、それらを使用するかどうかはユーザー次第です。マルチスレッド コードを作成するときは、それに関連するすべてのリスクと負債を想定します。コードがスレッドセーフであることを確認するのは、プログラマーの責任です

ここで言及している特定のケースは、かなり単純に思えます。私はスレッド プールを使用するのが好きなので、イベントを使用したソリューションを紹介します。実際のThreadオブジェクトを使用してこれを行うこともできますThread.Join。ここでスレッド A にいると仮定します。

void Xyz()
{
    SomeData dataFromB = null;
    ManualResetEvent finishedB = new ManualResetEvent(false);
    ThreadPool.QueueUserWorkItem(s =>
    {
        dataFromB = GetDataFromB();
        finishedB.Set();
    });

    SomeOtherData dataFromC = null;
    ManualResetEvent finishedC = new ManualResetEvent(false);
    ThreadPool.QueueUserWorkItem(s =>
    {
        dataFromC = GetDataFromC();
        finishedC.Set();
    });

    finishedB.WaitOne();
    finishedC.WaitOne();
    finishedB.Dispose();
    finishedC.Dispose();

    CallExternalDLL(dataFromB, dataFromC);
}

これは、操作全体が完了するまでブロックされます。これを UI スレッドから直接実行している場合は、このメソッド全体を別のワーカー スレッドから呼び出す必要があります。

于 2010-03-18T15:29:23.883 に答える
0

"I was sure it threw errors for trying to access things created on other threads." this statement is only valid for properties of controls. Generic variable can be accessed from any thread. Yes, it can cause problems (race conditions) when done incorrectly, but sometimes it is necessary. You should mark this variables as volatile, minimize access to them, use locks or Interlocked class. This is my advices :)

于 2010-03-18T15:27:06.623 に答える