关闭表单时出现异常(线程+调用)
Posted
技术标签:
【中文标题】关闭表单时出现异常(线程+调用)【英文标题】:Exception when closing Form (thread + invoke) 【发布时间】:2013-11-06 08:23:54 【问题描述】:我刚开始学习c#中的线程和方法调用,但遇到了一个我找不到解决方案的问题。
我制作了一个基本的 C# 表单程序,它通过启动一个线程并调用委托来不断更新和显示数字。
在 Form1_load 上启动新线程:
private void Form1_Load(object sender, EventArgs e)
t = new System.Threading.Thread(DoThisAllTheTime);
t.Start();
Public void DoThisAllTheTime(不断更新数字):
public void DoThisAllTheTime()
while(true)
if (!this.IsDisposed)
number += 1;
MethodInvoker yolo = delegate() label1.Text = number.ToString(); ;
this.Invoke(yolo);
现在,当我单击表单的 X 按钮时,出现以下异常:
'System.Windows.Forms.dll 中发生'System.ObjectDisposedException' 类型的未处理异常
无法更新已删除的对象'
虽然我确实检查了表单是否已处理。
编辑:我在解决问题的代码中添加了 catch (ObjectDisposedException ex)。 工作代码:
public void DoThisAllTheTime()
while(true)
number += 1;
try
MethodInvoker yolo = delegate() label1.Text = number.ToString(); ;
this.Invoke(yolo);
catch (ObjectDisposedException ex)
t.Abort();
【问题讨论】:
好吧,在计算(!this.IsDisposed)
之后,但在调用 this.Invoke(yolo);
之前,表单被处理掉了。欢迎来到赛车世界。
我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
@Joker_vD 我该如何解决这个问题?我认为检查会比方法调用更快。它也在 MSDN 上以这种方式使用。 (msdn.microsoft.com/en-us/library/…)
正如其他人已经说过这是一个种族问题,请参阅:***.com/questions/1874728/…
@Bart 不要指望 MSDN 示例代码是正确的。通常情况下,它不是。
【参考方案1】:
您对this.IsDisposed
的电话总是过期的。您需要拦截表单关闭事件并明确停止线程。那么你就完全不用做IsDisposed
测试了。
有很多方法可以做到这一点。就个人而言,我会使用System.Threading.Tasks
命名空间,但如果你想继续使用System.Threading
,你应该定义一个成员变量_updateThread
,并在你的加载事件中启动它:
_updateThread = new System.Threading.Thread(DoThisAllTheTime);
_updateThread.Start();
那么在你的闭幕式上:
private void Form1_Closing(object sender, CancelEventArgs e)
_stopCounting = true;
_updateThread.Join();
最后,将IsDisposed
测试替换为检查新的_stopCounting
成员变量的值:
public void DoThisAllTheTime()
MethodInvoker yolo = delegate() label1.Text = number.ToString(); ;
while(!_stopCounting)
number += 1;
this.Invoke(yolo);
【讨论】:
我尝试添加 't.abort();'到 Form1_closure,但这也无济于事。 @Bart:尝试设置一个标志,然后调用t.Join();
等待线程识别它。
我在其中添加了 catch (ObjectDisposedException ex)。这解决了问题。我会更新我的问题。
@Bart:正如 oefe 所说,这太令人发指了! :D
由于Invoke
正在阻塞等待主线程,如果在number += 1;
行上执行Form1_Closing
方法,这里就有死锁的可能。随着越来越多的工作代替这条线完成,僵局的机会就会增加。我通过使用BeginInvoke
而不是Invoke
在我的应用程序中修复了这个问题,因为BeginInvoke
不会阻止线程退出,因此Join
不会永远阻塞。【参考方案2】:
只需将此覆盖放在您的表单类中:
protected override void OnClosing(CancelEventArgs e)
t.Abort();
base.OnClosing(e);
【讨论】:
+1 一个不错的解决方案。要获取更多信息:请参阅***.com/questions/1874728/… @Alireza 谢谢哥们。答案与我从问题中获得的初学者技能兼容。但真的谢谢。干杯 正常场景关闭不得包括对Thread.Abort()
、Application.Exit()
等的调用。我已经看到了一个由此引起的错误——由于Environment.Exit()
spurios 而没有回滚事务在 OnClose()
事件处理程序中。【参考方案3】:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
Thread.CurrentThread.Abort();
【讨论】:
以上是关于关闭表单时出现异常(线程+调用)的主要内容,如果未能解决你的问题,请参考以下文章
Android:当我使用 AsyncTask 时出现“调用线程必须是准备好的 Looper 线程”错误