ale*_*oot 5 c# multithreading timer
我有一个启动System.Threading.Timer的应用程序,然后这个计时器每5秒从链接数据库读取一些信息并在主要应用程序形式上更新GUI;
由于System.Threading.Timer为Tick事件创建另一个线程,我需要使用Object.Invoke在主应用程序表单上更新用户界面,代码如下:
this.Invoke((MethodInvoker)delegate()
{
label1.Text = "Example";
});
Run Code Online (Sandbox Code Playgroud)
该应用程序工作得很好,但有时当用户关闭主窗体然后关闭应用程序时,如果timer_tick事件上的第二个线程正在更新主线程上的用户界面,则用户将获得ObjectDisposedException.
如何在关闭主窗体之前停止并关闭线程计时器,然后避免对象处置异常?
这是一个棘手的主张,因为您必须确保给定的Close事件具有以下内容
我以前遇到过这个问题而且我发现防止这个问题是非常有问题的,并且涉及很多混乱,难以维护的代码.相反,更容易捕获这种情况可能产生的异常.通常我通过如下包装Invoke方法来实现
static void Invoke(ISynchronizedInvoke invoke, MethodInvoker del) {
try {
invoke.Invoke(del,null);
} catch ( ObjectDisposedException ) {
// Ignore. Control is disposed cannot update the UI.
}
}
Run Code Online (Sandbox Code Playgroud)
如果你对后果感到满意,忽略这个例外就没有任何内在错误.也就是说,如果您已经处理好UI,那么它就不会更新了.我当然是:)
上面没有解决问题#2,但仍需要在您的代理中手动完成.使用WinForms时,我经常使用以下重载来删除该手动检查.
static void InvokeControlUpdate(Control control, MethodInvoker del) {
MethodInvoker wrapper = () => {
if ( !control.IsDisposed ) {
del();
}
};
try {
control.Invoke(wrapper,null);
} catch ( ObjectDisposedException ) {
// Ignore. Control is disposed cannot update the UI.
}
}
Run Code Online (Sandbox Code Playgroud)
注意
汉斯指出,ObjectDisposedException
这不是可以从Invoke方法中提出的唯一例外.还有其他几个,至少包括InvalidOperationException
你需要考虑处理.
System.Timers.Timer 是一个可怕的类。没有什么好的方法可以可靠地阻止它,总是有一场竞赛,你无法避免它。问题在于它的 Elapsed 事件是从线程池线程引发的。您无法预测该线程何时实际开始运行。当您调用 Stop() 方法时,该线程很可能已经添加到线程池中,但尚未开始运行。它受 Windows 线程调度程序和线程池调度程序的约束。
你甚至不能通过任意延迟关闭窗口来可靠地解决它。在最极端的情况下,线程池调度程序可以将线程的运行延迟最多 125 秒。您可以通过延迟关闭几秒钟来减少异常的可能性,它不会为零。延迟 2 分钟关闭是不现实的。
只是不要使用它。要么使用 System.Threading.Timer 并将其设为一次性计时器,然后在事件处理程序中重新启动。或者使用System.Windows.Forms.Timer,它是同步的。
此处应选择 WF 计时器,因为您使用 Control.Invoke()。在您的 UI 线程空闲之前,委托目标不会开始运行。与 WF 计时器的行为完全相同。
归档时间: |
|
查看次数: |
6209 次 |
最近记录: |