WinForm中,线程调用已释放部分的问题,望各位高手帮忙!!

雪狼孤竹 2015-03-18 02:34:58
C# 小弟没有实际经验,虽然很久之前学习过,但是没有经历过现实的项目。目前单位有向C# 方向发展的意向,有个简单的小项目要用C#来实现。其间,用到了线程处理,比较简单的。但是在使用过程中,有个问题,一直不知道怎么来处理,虽然可以避之,也不影响结果。但总觉得是个疙瘩,不是很舒服。

简单描述,登录窗体,通过线程获取管理母卡的卡号,验证结束后,登录软件系统。
其中的处理是,窗体显示,线程启动,得到正确的卡号后,验证通过,关闭线程,关闭窗口。
问题就出在关闭线程,关闭出口中,会提示 “无法访问已释放的对象 w_login”。
做了一些限制,但是只是减少了该情况发生的几率,并没有完全解决掉。
希望大牛能够给个彻底解决的方向,小弟先在此谢谢了!!!!!!


下面是部分代码:
线程中的执行部分
//发送寻卡指令
private void findCard()
{
string strCardCode = "";
int outTime = 1500; //超时时间

while (bRunMark) //启动后该变量为true
{
//*********************************
// 数据处理
//*********************************
if (bRunMark) //为了防止问题发生 在此做了限定 变量为false
{
try
{
this.Invoke((EventHandler)(delegate
{
if (VariableClass.CheckFormIsOpen("w_login")) //在此做了 该窗口关闭的限定 如果窗口关闭 此条件即为false
{
if (getPerson(strCardCode) == 1) //w_login中的一个自定方法
{
//目的变量赋值
}
else
{
//目的变量赋值
}
}
}));
}
catch (Exception ex)
{
MessageBox.Show("错误:" + ex.Message);
return;
}
}
}
}


准备结束退出窗口的部分
private void btnOk_Click(object sender, EventArgs e)
{
//*********************
// 数据处理
//*********************

//成功关闭窗体
bRunMark = false;
this.Close();
}
}
...全文
524 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
Peter石 2015-03-26
  • 打赏
  • 举报
回复
没看出来线程在什么地方开始的,不好梳理现场生命周期。
雪狼孤竹 2015-03-21
  • 打赏
  • 举报
回复
引用 26 楼 sxl_88 的回复:
用委托的异步方式调用即可
谢谢,有时间一定看看这部分。
sxl_88 2015-03-20
  • 打赏
  • 举报
回复
用委托的异步方式调用即可
雪狼孤竹 2015-03-19
  • 打赏
  • 举报
回复
引用 22 楼 xian_wwq 的回复:
[quote=引用 20 楼 Snowwolf_119 的回复:] [quote=引用 16 楼 wangmoxhn 的回复:] //成功关闭窗体 bRunMark = false; //在此添加 thread是你的线程对象 等待线程退出后才close窗体 thread.Join() this.Close();
非常抱歉,刚刚没太仔细看。thread.Join()和我的延时类似,作用确是截然不同的。 我要找的可能就是这个让线程自然结束的,虽然有时候它会处在电脑进程的不同位置,但是它都会自行结束C#中的线程,不会造成故障。 同上,此贴仍会在下周结贴,不知是否还有其它方式解决此类问题?[/quote] 线程要安全退出,基本原则就是让线程自行结束, 将bRunMark = false; 不能保证线程立刻退出, 延时的方法不可取,如果在线程的while逻辑中有比较耗时的处理, 那么延时后有可能还没有退出。 使用thread.Join(),耐心等待线程自行结束 [/quote] 确实如此,也加过很多退出的限定,但是进程本身有自己的进度。往往都是运行到问题部分后,才加上退出限定。但此时,窗体已经关闭了,造成了问题。 加延时,当时的想法是让线程在未执行窗体关闭前自行结束,但是,存在问题是电脑本身进程处理的时间如果大于这个延时,就仍然会有问题产生。 我C# 多线程这部分刚刚了解,还在学习中。 谢谢回帖!!
雪狼孤竹 2015-03-19
  • 打赏
  • 举报
回复
引用 23 楼 wyd1520 的回复:
[quote=引用 21 楼 Snowwolf_119 的回复:] [quote=引用 19 楼 wyd1520 的回复:] 你看看你的线程有没有设成IsBackground=true吧。要没请加上这个。要不然你关了窗体线程还在跑。
目前没有设置成后台线程,因为前后台线程在处理上没有本质的区别,占用资源也一样。 本贴问题,不是关闭窗口,遗不遗留线程,而是如何安全结束线程,不造成不必要的问题。 不过还是谢谢你的回帖!![/quote] 发现你好牛B,大家都搞不定了。。。。前后台线程区别就是关闭窗口,要不要留线程的问题,而你的代码一直在while true...又没作安全锁。。。你所说的安全退出。没看到你有什么安全退出东西。如果你非得要这么干。那你要么配合用MulaEventSet或用BackgroundWork你就能随意控制线程是否要安全退出。光靠一个bool值肯定是不安全退出地。。。 [/quote] 牛不敢,估计没有你牛。 改成后台,能把这个贴结了,你就牛。 安全退出,可能我没你厉害,还不会说话,用词不当。 抱歉!! 解决问题,才叫牛,别的不多说了!!!!
本拉灯 2015-03-19
  • 打赏
  • 举报
回复
引用 21 楼 Snowwolf_119 的回复:
[quote=引用 19 楼 wyd1520 的回复:] 你看看你的线程有没有设成IsBackground=true吧。要没请加上这个。要不然你关了窗体线程还在跑。
目前没有设置成后台线程,因为前后台线程在处理上没有本质的区别,占用资源也一样。 本贴问题,不是关闭窗口,遗不遗留线程,而是如何安全结束线程,不造成不必要的问题。 不过还是谢谢你的回帖!![/quote] 发现你好牛B,大家都搞不定了。。。。前后台线程区别就是关闭窗口,要不要留线程的问题,而你的代码一直在while true...又没作安全锁。。。你所说的安全退出。没看到你有什么安全退出东西。如果你非得要这么干。那你要么配合用MulaEventSet或用BackgroundWork你就能随意控制线程是否要安全退出。光靠一个bool值肯定是不安全退出地。。。
xian_wwq 2015-03-19
  • 打赏
  • 举报
回复
引用 20 楼 Snowwolf_119 的回复:
[quote=引用 16 楼 wangmoxhn 的回复:] //成功关闭窗体 bRunMark = false; //在此添加 thread是你的线程对象 等待线程退出后才close窗体 thread.Join() this.Close();
非常抱歉,刚刚没太仔细看。thread.Join()和我的延时类似,作用确是截然不同的。 我要找的可能就是这个让线程自然结束的,虽然有时候它会处在电脑进程的不同位置,但是它都会自行结束C#中的线程,不会造成故障。 同上,此贴仍会在下周结贴,不知是否还有其它方式解决此类问题?[/quote] 线程要安全退出,基本原则就是让线程自行结束, 将bRunMark = false; 不能保证线程立刻退出, 延时的方法不可取,如果在线程的while逻辑中有比较耗时的处理, 那么延时后有可能还没有退出。 使用thread.Join(),耐心等待线程自行结束
雪狼孤竹 2015-03-19
  • 打赏
  • 举报
回复
引用 19 楼 wyd1520 的回复:
你看看你的线程有没有设成IsBackground=true吧。要没请加上这个。要不然你关了窗体线程还在跑。
目前没有设置成后台线程,因为前后台线程在处理上没有本质的区别,占用资源也一样。 本贴问题,不是关闭窗口,遗不遗留线程,而是如何安全结束线程,不造成不必要的问题。 不过还是谢谢你的回帖!!
雪狼孤竹 2015-03-19
  • 打赏
  • 举报
回复
引用 16 楼 wangmoxhn 的回复:
//成功关闭窗体 bRunMark = false; //在此添加 thread是你的线程对象 等待线程退出后才close窗体 thread.Join() this.Close();
非常抱歉,刚刚没太仔细看。thread.Join()和我的延时类似,作用确是截然不同的。 我要找的可能就是这个让线程自然结束的,虽然有时候它会处在电脑进程的不同位置,但是它都会自行结束C#中的线程,不会造成故障。 同上,此贴仍会在下周结贴,不知是否还有其它方式解决此类问题?
本拉灯 2015-03-19
  • 打赏
  • 举报
回复
你看看你的线程有没有设成IsBackground=true吧。要没请加上这个。要不然你关了窗体线程还在跑。
雪狼孤竹 2015-03-19
  • 打赏
  • 举报
回复
引用 16 楼 wangmoxhn 的回复:
//成功关闭窗体 bRunMark = false; //在此添加 thread是你的线程对象 等待线程退出后才close窗体 thread.Join() this.Close();
这个我在之前已经提过,不过还是谢谢了!
引用 17 楼 wyd1520 的回复:
VariableClass 这是啥东西
VariableClass 是我定义的一个静态公共类,内部放一些公共变量,方法。 经过测试,目前采用的是,在线程中加入退出限定,在人为要求退出后,给一定量的时间,让线程结束的方式来做这部分。故障仍会出现,但几率相对小了很多。具体代码只是在bRunMark变为false后,加入System.Threading.Thread.CurrentThread.Join(200);,之后才关闭窗体。其中200的时间会根据实际情况做相应调整。 在此谢谢以上回帖的朋友的帮助,并且此贴暂时并不会结贴。虽然就目前来看,所述方式效果较好,但仍然无法避免故障的出现。 本贴将于下周结贴,在此期间,望高手能提出更好的解决方式,避免故障的发生。小弟在此谢过!!
本拉灯 2015-03-18
  • 打赏
  • 举报
回复
VariableClass 这是啥东西
wangmoxhn 2015-03-18
  • 打赏
  • 举报
回复
//成功关闭窗体 bRunMark = false; //在此添加 thread是你的线程对象 等待线程退出后才close窗体 thread.Join() this.Close();
於黾 2015-03-18
  • 打赏
  • 举报
回复
Invoke是同步的方式,线程要等待主线程执行完委托,才继续执行,而这时主窗口已经释放了,当然就报错了 BeginInvoke是异步的,是先放到线程池里,等主线程有空的时候再调用,那么等它调用的时候主线程已经退出了,当然就不去调用了
雪狼孤竹 2015-03-18
  • 打赏
  • 举报
回复
引用 13 楼 Z65443344 的回复:
如果是登陆窗体,用户手动关闭,你就应该结束进程,而不是把主窗体再显示出来 除非你的线程正常走完,验证通过了,这时才应该关闭登陆窗体并显示主窗体
是得让进程自己走完,目前我想到的,只是在bRunMark变成false后,做点延时,给进程时间走完,之后再关闭窗体。 刚刚也试了 进程.Abort() ,应该也可。不过刚刚问题部分,在此方法执行后,报出“正在停止进程”提示,也是try……catch捕获的。 这两天也在网上查过,this.BeginInvoke() 就不会截获异常,但this.Invoke()就会截获异常。
於黾 2015-03-18
  • 打赏
  • 举报
回复
如果是登陆窗体,用户手动关闭,你就应该结束进程,而不是把主窗体再显示出来 除非你的线程正常走完,验证通过了,这时才应该关闭登陆窗体并显示主窗体
雪狼孤竹 2015-03-18
  • 打赏
  • 举报
回复
引用 9 楼 duanzi_peng 的回复:
访问w_login 对象之前 判断是否 已经释放了不就行了,没释放 就访问;释放了 就不访问。
这个好像没有那么简单吧,因为就目前我的理解,线程是并行发生的,它本身是有自己的进度的。 虽然我可以给它一定的限制,但是我无法掌控其进度。上面在 this.Invoke 方法执行前,就有一个窗口是否已经关闭的验证,但是还是会小几率的出现题目中的问题。 也就是说,我的验证在线程的进度之后变化的,所以它会执行那个已经释放的对象w_login中的方法,致使它报错。
雪狼孤竹 2015-03-18
  • 打赏
  • 举报
回复
引用 7 楼 Z65443344 的回复:
想安全停掉线程,你应该在线程的while循环里写代码,让它自己跳出循环 既然你用了while (bRunMark)而不是while (true),把它变成false,线程不就退出了吗 用abort的方式有风险,比如线程里使用了非托管资源,那么在外部强制结束线程,可能会使这部分资源无法得到释放(释放资源的代码还没有走,线程就被强制关闭了) 如果你这个窗口是主窗口,想要关闭窗口后不留下死进程 也可以这样 Prosess.GetCurrentProcess.Kill();//杀死当前进程,进程都杀死了,当然所有线程都会被强制关闭,引用的资源也都会被回收掉
其实按理说,bRunMark 给出了false的值,线程就应该正常关闭。但是实际上,它当前处理的部分得执行完才能接受bRunMark的false,停掉这个循环。我这部分代码其实是在登录窗口中,其背后还有一个未获焦点的主窗体。 Prosess.GetCurrentProcess.Kill(); 这个还是谢谢您,可能未来会用到。
於黾 2015-03-18
  • 打赏
  • 举报
回复
所以干脆就不去访问w_login,而只去取这个窗体中定义的bool变量,是false就退出线程就好了 线程里要访问窗体对象,是会出现各种问题
exception92 2015-03-18
  • 打赏
  • 举报
回复
访问w_login 对象之前 判断是否 已经释放了不就行了,没释放 就访问;释放了 就不访问。
加载更多回复(8)

110,536

社区成员

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

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

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