C#中的跨线程事件处理

我正在使用一个框架,该框架在一个单独的线程中运行自己的事件调度程序。 框架可能会生成一些事件。

class SomeDataSource { public event OnFrameworkEvent; void FrameworkCallback() { // This function runs on framework's thread. if (OnFrameworkEvent != null) OnFrameworkEvent(args); } } 

我想将这些事件传递给Winforms线程上的Winforms对象。 我显然检查InvokeRequired并在必要时将其发送到Winforms线程。

 class SomeForm : Form { // ... public void SomeAction(SomeArgs args) { if (InvokeRequired) { BeginInvoke(new Action(SomeAction), args); return; } // ... } } 

现在事件可能在表单处于关闭状态时传递,这会导致各种问题,所以我在Winforms线程上从框架的事件源取消注册表单的事件处理程序,如下所示:

 var form = new SomeForm(); var src = new SomeDataSource(); // ... src.OnFrameworkEvent += form.SomeAction; form.Closing += (sender, eargs) => src.OnFrameworkEvent -= form.SomeAction; 
  1. 现在, 这种方法是线程安全的吗? 如果表单处于关闭状态,而外部线程调用BeginInvoke ,如果表单关闭,调用是否仍会排队等待执行? (这意味着我仍然有机会遇到同样的问题)

  2. 是否有更好的方法或推荐的跨线程事件处理模式?

不它不是。 线程可能只是在您取消注册并关闭表单时执行事件处理程序。 赔率很小,但不是零。 在关闭表单之前必须先停止线程。 如果您不想中止它,则必须通过取消FormClosing事件来保持表单处于打开状态,然后让线程的完成回调关闭表单。

查看此主题以获取更多信息。

您可以将此代码添加到构造函数CheckForIllegalCrossThreadCalls = false; 并且不会抛出exception。

我没有使用具有自己的事件调度程序的框架,但我对自己创建的线程有自己的经验。 这是我的经历

  1. 这种方法不是线程安全的。 即使程序本身已关闭,仍将调用调用。 我在任务管理器中看到这个(在程序关闭后如你所说)作为挂线程。 (即使你也从任务管理器中杀了程序。) 我不得不单独杀死那些线程。

  2. 当表单关闭时,您必须终止调度程序线程,以便在该线程中发生任何错误时它不会挂起。

     form.Closing += (sender, eargs) => src.OnFrameworkEvent -= form.SomeAction; // pseudo-code (find c# equivalent) if (dispatcherthread.isrunning) dispatcherThread.kill();