多线程操作窗体控件时,此时关闭窗体会导致报错,有什么方法可以解决么?

hnlnbukn 2013-05-10 04:09:04
因为是第一次接触多线程的项目,对这方面的东西不太了解。

基本的流程是 利用Timer定时对数据库进行检索,然后将数据显示到窗体里的DataGridView中。

但是现在遇到这么一个问题,在窗体关闭的时候,this.Invoke方法会报错:“无法访问已释放的对象”。在FormClosing中添加了对Timer对象的中断后,出现这个错误的可能性减小了,但是仍会出现。

猜测是托管线程正在执行更新DataGridView的操作的时候,主线程关闭了窗口,将对象释放了。

试了一下在this.Invoke前添加了this.isDisposed的判断,但是还是有极小的可能会出现这个错误。请问下有什么方法可以让这个问题不会再出现呢?
...全文
721 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
Sam830131 2013-06-10
  • 打赏
  • 举报
回复
试试把线程设置为后台线程 IsBackground=true 这样窗体关闭,线程就会跟着关闭了
wzqwww 2013-06-10
  • 打赏
  • 举报
回复
先对话线程,再窗体。Timer就是重新开了个线程在跑了,你把它先释放掉再关,就O啦
朝耕暮耘 2013-06-08
  • 打赏
  • 举报
回复
可以设置一个标识位,可以在窗体关闭时先停止timer,还可以在timer里面加一个锁
hnlnbukn 2013-06-08
  • 打赏
  • 举报
回复
引用 8 楼 sp1234 的回复:
你很能瞎折腾。 注销Timer的监听上面已经说到了,问题是就算是在访问到窗口,为什么会出现“访问已释放的对象”的异常?到底是什么对象被你手工释放了? 当你注销了Timer上的监听方法,也就是说没有什么东西引用窗口之后,过一段时间(例如5秒钟)窗体内的一切就会被GC销毁。你提前收工释放什么东西干什么呢?如果你手工释放,那么你就应该小心写代码来检测、回避。 你没有贴出出现异常的代码,具体的东西很难以判断。但是可以推断出现异常的代码的地方,你可以很容易找到你的代码手工释放的痕迹。
没有使用Dispose()。相反我倒是在回调方法中判断了this.Disposed的值,但是仍然会产生这个问题,只不过是问题出现的次数减少了。回调的方法中有段很耗费性能的Table转型成对象的代码。
mansheng 2013-06-08
  • 打赏
  • 举报
回复
我也是出现过这样的一个问题,关闭了打开他还是在,一段时间后就报像你说的那种错误,后来我是这么做的,在释放窗体或者关闭窗体的地方把timer.stop,timer.enable=false,timer.dispose(),从此后再也没有报这个错误了,LZ你也试试。goodluck!
游戏人间 2013-05-25
  • 打赏
  • 举报
回复
3楼是正确的。先停止计时器,再关闭窗体。
hnlnbukn 2013-05-24
  • 打赏
  • 举报
回复
引用 4 楼 u010383116 的回复:
把线程设成后台线程
Timer可以设置成后台么?而且线程里面是需要对控件内容进行更新的
  • 打赏
  • 举报
回复
引用 楼主 hnlnbukn 的回复:
猜测是托管线程正在执行更新DataGridView的操作的时候,主线程关闭了窗口,将对象释放了。
如果你是正常地编程,主线程关闭了窗口,但是此时其他正在执行的代码还直接引用它,它根本不会释放,你完全可以访问已经关闭的窗口里的控件,毫无问题。除非你画蛇添足地手工释放了什么。 可能有些人不去了解Dispose()方法里边到底包含什么内容,不去理解每一个具体的对象的“释放”的含义是什么,就仅仅因为这个词儿听起来挺时髦的,就去调用Dispose()。这种习惯应该改掉。除非你知道Dispose()内涵,知道如何必要地使用它,否则不要胡乱调用Dispose()。
  • 打赏
  • 举报
回复
你很能瞎折腾。 注销Timer的监听上面已经说到了,问题是就算是在访问到窗口,为什么会出现“访问已释放的对象”的异常?到底是什么对象被你手工释放了? 当你注销了Timer上的监听方法,也就是说没有什么东西引用窗口之后,过一段时间(例如5秒钟)窗体内的一切就会被GC销毁。你提前收工释放什么东西干什么呢?如果你手工释放,那么你就应该小心写代码来检测、回避。 你没有贴出出现异常的代码,具体的东西很难以判断。但是可以推断出现异常的代码的地方,你可以很容易找到你的代码手工释放的痕迹。
我要坚强 2013-05-24
  • 打赏
  • 举报
回复
帖上你的代码
本拉灯 2013-05-10
  • 打赏
  • 举报
回复
IsBackground=true
我要坚强 2013-05-10
  • 打赏
  • 举报
回复
把线程设成后台线程
viki117 2013-05-10
  • 打赏
  • 举报
回复
在关闭窗口的时候停止掉计时器 timer.Stop();再this.Close(); 这个错误是close窗体的时候,已经释放了控件,但是timer没有停止,timer在访问控件的时候,抱错
hnlnbukn 2013-05-10
  • 打赏
  • 举报
回复
但是现在的问题可能是关闭、释放的操作和控件访问的操作时间一致了。 控件访问的方法里面对标志进行了判断,然后FormClosing中变更了标志,再是窗口关闭,控件被释放,然后再对控件访问。。。结果报错 取消事件订阅也是,可能在取消的同时,已经开始了访问。然后依然报错。 这个流程只是推测,因为设置过标志位但是依然会报出错误。调试的时候没有出现过这个错误。
gomoku 2013-05-10
  • 打赏
  • 举报
回复
在FormClosing中取消事件订阅等等,目的是为了让线程们不用再更新DataGridView了。 除了this.IsDisposed,你也可以自己设置一个标志,FormClosing中设置后,就不让访问窗口元素了。
在码农的生活中,很多级码农都有这样的经历,被一个小小的技术问题拦住,然后进度跟不上了,被老板XXXX一大通了。心情不爽了。 好吧,这个曾经是我遇到拦路虎之一。但事实上不是什么大技术。技术就是一层纸,破了就破了。 这是一个关于如何跨窗体操作控件或过程的一个例子。比如,你想用窗体A的按键来执行窗体B的文本框变色。 Imports System Imports System.Threading Imports System.Text Public Class Form1 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load CheckForIllegalCrossThreadCalls = False '不写这行,出错,不允许线程的数据写到TextBox1.Text 中去。 Form2.Show() End Sub Private Sub form1_FormClosing(sender As Object, e As EventArgs) Handles Me.FormClosing ' If runThread.IsAlive = True Then runThread.Abort() End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click '用的是委托方式 Me.Invoke(New MethodInvoker(AddressOf THREAD2)) End Sub Private Sub THREAD2() Static j As Integer j = j + 1 TextBox1.Text = " 这是 [线程] 操作" & vbCrLf & _ " Button2被点了: " & j & " 次" & vbCrLf & "要求是from2.textbox.text= textbox1.text 。[问题]但为什么不能成功显示呢?" End Sub Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged Form2.TextBox1.Text = TextBox1.Text End Sub Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click Static j As Integer j = j + 1 TextBox1.Text = " 这是 [非线程] 操作" & vbCrLf & _ "Button3 点击了: " & j & " 次" & vbCrLf & _ "要求是from2.textbox.text= textbox1.text, 可以成功显示,这个是对的。" End Sub End Class

111,076

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧