C#中的跨线程事件处理

时间:2010-01-29 00:45:10

标签: c# winforms multithreading event-handling

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

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. 是否有更好的方法或推荐的跨线程事件处理模式?

3 个答案:

答案 0 :(得分:4)

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

查看this thread了解详情。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

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

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

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

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