1

メイン スレッドのセカンダリ スレッドからイベントを呼び出すことができません。イベント ハンドラはメイン スレッドでは実行されません。私が間違っていることについて誰かが私にいくつかの指針を与えることができますか?

ありがとう

namespace ThreadSyncExample
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("MainThread: " + System.Threading.Thread.CurrentThread.ManagedThreadId);

      Execute execThe = new Execute();
      execThe.FinishedThread += (src, arg) =>
      {
        //This shoould be executed on MainThread right?
        Console.WriteLine("Thread Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
      };

      execThe.Run();
      Console.ReadKey();
    }

  }


  class Execute
  {
    public void Run()
    {
      Thread exec = new Thread(() =>
      {
        Console.WriteLine("Worker Thread : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        OnFinishedThread();
      });

      exec.Start();
    }

    public event EventHandler FinishedThread;
    protected virtual void OnFinishedThread()
    {
      if (null != FinishedThread)
      {
        EventArgs args = new EventArgs();
        FinishedThread(this, EventArgs.Empty);
      }
    }
  }
}
4

2 に答える 2

2

C# イベントは基本的にデリゲートの使いやすいコレクションであり、イベントを "起動" すると、ランタイムがすべてのデリゲートをループして一度に 1 つずつ起動します。

したがって、OnFinishedThread イベント ハンドラーはワーカー スレッドで呼び出されます。

メインスレッドでイベントが必要な場合は、そうする必要がありますInvoke()

編集 :

フォームまたは WPF にアクセスできないようです (したがって、どちらにもアクセスできませんInvoke()) 。

そのため、スレッド同期プロセスによってメイン スレッドへの呼び出しを手動でマーシャリングする必要があります。一般的には痛いです。

おそらく最も簡単な解決策は、BackgroundWorkerを使用することです。これにより、メイン スレッドへの呼び出しを手動でマーシャリングする必要がなくなります。

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
    // call the XYZ function
    e.Result = XYZ();
};
worker.RunWorkerCompleted += (sender, e) =>
{
    // use the result of the XYZ function:
    var result = e.Result;
    // Here you can safely manipulate the GUI controls
};
worker.RunWorkerAsync();
于 2012-10-03T13:18:25.857 に答える
1

FinishedThread()イベントハンドラーは、Execute.Run()が実行されるのと同じスレッドで実行されます。main()でFinishedThreadイベントハンドラーの本体を定義したからといって、main()が何らかの形でその実行コンテキストを定義しているわけではありません。

スレッドマーシャリングを実行するために使用できるいくつかのメカニズム:

  1. system.windows.forms.controlを使用し、Invokeメソッドを使用して、コントロールが作成されたスレッドへの関数呼び出しをマーシャリングします。内部的には、これはWindowsメッセージループの機能を使用して実際のマーシャルを処理します
  2. 同期プリミティブを使用して、マーシャリングを手動で処理します。

マーシャリングの詳細については、すでに述べたことを繰り返すのではなく、この回答を確認してください。

手動でスレッドにマーシャルする

于 2012-10-03T13:19:06.153 に答える