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;
现在,这种方法是线程安全的吗? 如果表单处于关闭过程中,并且外部线程调用BeginInvoke
,则如果表单关闭,调用是否仍然排队等待执行? (这意味着我仍然有机会遇到同样的问题)
针对跨线程事件处理有更好的方法或推荐模式吗?
不它不是。 线程可能正在执行事件处理程序,而您取消注册并关闭表单。 小的可能性,但不是零。 在关闭表单之前,必须先停止线程。 如果您不想中止它,您必须通过取消FormClosing事件来保持表单打开,然后让线程的完成回调关闭表单。
检查此线程获取更多信息。
您可以将此代码添加到构造函数CheckForIllegalCrossThreadCalls = false;
并且不会抛出异常。
我没有使用自己的事件调度器的框架,但我有我自己的经验与我创建的线程。 这是我的经验
这种方法不是线程安全的。 即使程序本身已关闭,调用仍将被调用。 我在任务管理器(在程序关闭后,如你所说)看到了这个线程挂起。 (即使你也从任务管理器中终止程序)。 我不得不稍后杀死那些线程。
当表单关闭时,必须杀死调度程序线程,以便在该线程中发生任何错误时不会挂起。
form.Closing += (sender, eargs) => src.OnFrameworkEvent -= form.SomeAction;
// pseudo-code (find c# equivalent)
if (dispatcherthread.isrunning)
dispatcherThread.kill();