2010-01-29 30 views
11

我正在使用一个在独立线程中运行其自己的事件分派器的框架。该框架可能会产生一些事件。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. 是否有更好的方法或推荐的模式用于跨线程事件处理?

回答

4

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

检查this thread了解更多信息。

+0

我喜欢这种方法。我喜欢在线程完成时使用回调方法。 – 2010-01-29 18:46:21

1

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

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

  2. 当窗体关闭时,必须杀死调度程序线程,以便在该线程中发生任何错误时不会挂起。

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

如果调度程序线程需要保持活动状态以处理其他Winforms,该怎么办? – 2010-01-29 01:15:46

+0

恐怕是这样。我有多种形式倾听同一个事件源。 – 2010-01-29 01:19:24

+0

如果我正确理解你说的话,那么将线程的IsBackground属性设置为true将防止悬挂线程。 – 2010-01-29 18:44:51

2

您可以将此代码添加到构造函数CheckForIllegalCrossThreadCalls = false;中,不会抛出异常。