从工作线程调用主线程上的事件

时间:2012-10-03 13:07:35

标签: c# multithreading thread-safety

我在主线程中从辅助线程调用事件时遇到问题。事件处理程序不在主线程上执行。任何人都可以给我一些关于我做错的指示。

由于

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);
      }
    }
  }
}

2 个答案:

答案 0 :(得分:1)

C#事件基本上只是一个易于使用的代理集合,“触发”事件只会导致运行时循环遍历所有代理并一次触发它们。

因此,在Work线程上调用了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();

答案 1 :(得分:1)

FinishedThread()事件处理程序将在执行Execute.Run()的同一线程上执行。仅仅因为你在main()中定义了FinishedThread事件处理程序的主体并不意味着main()以某种方式定义了它的执行上下文。

您可以使用一些机制来执行线程编组:

  1. 使用system.windows.forms.control并使用Invoke方法将函数调用封送回创建控件的线程。在幕后,这将使用Windows消息循环的功能来处理实际的编组
  2. 使用同步原语手动处理编组。
  3. 不要重复已经说明的内容,请查看此答案以获取有关编组的更多信息:

    Marshall to a thread manually