求解winform界面诡异卡死的原因

twtyypmb123 2017-12-27 03:04:22
在程序中为了不阻塞界面,就用了类似以下代码

( new System.Threading.Thread( () =>
{
Action();
this.BeginInvoke();
} ) ).Start();

Action会调用第三方库,当某些条件时,会弹出一个对话框,提示错误,如果在主线程里调用这个方法,当然就是模态框了,现在遇到的问题是
1.这种多线程里面弹出模态框,而实际上表现出来的又没有模态,这种调用方式有无错误?
2.当某个时刻弹出提示框时,界面卡死了,而且主界面的timer也失效了,所以怀疑是提示框又把主线程阻塞了,但是主界面和提示框又能互相点击切换,点击了提示框上的按钮关闭提示框,主界面又恢复了,这是什么原因?
...全文
1721 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
SoulRed 2017-12-29
  • 打赏
  • 举报
回复
的确很诡异,正常用invoke调用UI是正确的做法。你可能在业务逻辑上有错误。建议检查下你的业务逻辑。。
tonysungood000 2017-12-28
  • 打赏
  • 举报
回复
以前碰到过这些问题:
1.子线程发出了阻断式操作(如提示、选择式提示窗体)
2.子线程与主线程交叉(共用独占式资源)。
3.窗体响应是依赖于消息机制的。

建议:
1.子线程只负责后台,主线程负责响应。
2.需阻断式操作时发信号量,不要直接控制窗体(任何模式、非模式本质都是窗体)。
3.主线程(或主窗体)接收信号量,负责提示及响应。
4.主线程(或主窗体)待用户响应后发信号量,子线程接收信号量再决定后续逻辑。
关键是:图形界面的事交给主线程(或主窗体),线程间各负其责,不要交叉,政令多出,越俎代庖。

[主界面上的按钮等响应是依赖于窗体消息机制的,占用的是主线程,不是分布式的。timer 控件我记得是依附于主线程的(记不清了)]
threenewbee 2017-12-28
  • 打赏
  • 举报
回复
begininvoke会执行同步的代码,如果其中代码耗时很大,那么就会卡。
twtyypmb123 2017-12-28
  • 打赏
  • 举报
回复
引用 10 楼 sp1234 的回复:
[quote=引用 楼主 x3230835 的回复:] 1.这种多线程里面弹出模态框,而实际上表现出来的又没有模态,这种调用方式有无错误? 2.当某个时刻弹出提示框时,界面卡死了,而且主界面的timer也失效了,所以怀疑是提示框又把主线程阻塞了,但是主界面和提示框又能互相点击切换,点击了提示框上的按钮关闭提示框,主界面又恢复了,这是什么原因?
假设你都是自己使用 c# 开发的,那么你在所谓action 实际执行的代码中,肯定会写类似
control.Invoke((Action)delegate
{
    模态对话框;
    继续处理;
    异步处理;
});
这类代码。 也就是说你的 action 首先是支持非 UI 线程,那么你就能在这里放心地使用 action。而假设你吊用别人的“库”代码并不支持非 UI 线程,那么就不得不把它整体放到主线程去执行,那么只好整体“怪他咯”。没有别的办法。 比如说以前我们在 c# 中经常要调用 Excel 来出一些东西,但是我们发现任何调用代码都要在 UI 线程来调用,哪怕仅仅是调用它做个生产资源规划计算, 或者仅仅是保存一下处理结果到文件,没有界面要求,也必须在 UI 线程来调用。 那么这就得这么调用。如果在子线程调用它,代码会“卡死”甚至出现各种各样的意外的崩溃。[/quote]首先谢谢回答,现在就是遇到这种问题,从现象上看,应该属于你说的不支持非UI线程调用,因为要做自动调用且不阻塞界面,所以才这样做,也许该和客户沟通下这个功能无法实现,毕竟第三方库是他们找人提供的,另外你提到的Excel的问题,最后是解决了多线程还是仍然用主线程执行?想看方法
twtyypmb123 2017-12-28
  • 打赏
  • 举报
回复
引用 7 楼 caozhy 的回复:
begininvoke会执行同步的代码,如果其中代码耗时很大,那么就会卡。
我例子当中的begininvoke没有问题,只是Action有问题,Action本来是获取数据,但报错时会以messagebox弹窗
  • 打赏
  • 举报
回复
假设说“第三方库”是上面的
control.Invoke(....)
方式执行,那么你在子线程中调用 action,你的 UI 主线程也会被阻塞,并不会产生你说的“而实际上表现出来的又没有模态”这个现象。那么这个时候你就不存在这个担心了。 所以这个担心,前提是“第三方库”首先就跟 .net 不完全兼容。这时候你要决定敢不敢在子线程中调用它,就要看测试来定。
  • 打赏
  • 举报
回复
“多线程里面弹出模态框,而实际上表现出来的又没有模态,这种调用方式有无错误?”这其实要分不同目的来看,首先从业务逻辑上看这能不能接受,如果不能接受则肯定是个 bug。其次从技术上来看,这样会不会带来运行时错误,程序不稳定,如果是的话那么也是 bug,如果不会造成程序不稳定那么就不算是技术上的bug。
  • 打赏
  • 举报
回复
引用 楼主 x3230835 的回复:
1.这种多线程里面弹出模态框,而实际上表现出来的又没有模态,这种调用方式有无错误? 2.当某个时刻弹出提示框时,界面卡死了,而且主界面的timer也失效了,所以怀疑是提示框又把主线程阻塞了,但是主界面和提示框又能互相点击切换,点击了提示框上的按钮关闭提示框,主界面又恢复了,这是什么原因?
假设你都是自己使用 c# 开发的,那么你在所谓action 实际执行的代码中,肯定会写类似
control.Invoke((Action)delegate
{
    模态对话框;
    继续处理;
    异步处理;
});
这类代码。 也就是说你的 action 首先是支持非 UI 线程,那么你就能在这里放心地使用 action。而假设你吊用别人的“库”代码并不支持非 UI 线程,那么就不得不把它整体放到主线程去执行,那么只好整体“怪他咯”。没有别的办法。 比如说以前我们在 c# 中经常要调用 Excel 来出一些东西,但是我们发现任何调用代码都要在 UI 线程来调用,哪怕仅仅是调用它做个生产资源规划计算, 或者仅仅是保存一下处理结果到文件,没有界面要求,也必须在 UI 线程来调用。 那么这就得这么调用。如果在子线程调用它,代码会“卡死”甚至出现各种各样的意外的崩溃。
楚楚3107 2017-12-28
  • 打赏
  • 举报
回复
用委托,不要跨UI使用线程。 this.Invoke(new delegate_ShowContent(this.richTextBox1.AppendText),(str + "\r\n"));
twtyypmb123 2017-12-27
  • 打赏
  • 举报
回复
引用 5楼Jason_Mao1 的回复:
用委托 或者 线程 。如果要处理大数据 或者 要等待很长时间就用异步,这样可以缓解界面假死想象。希望能帮助到你。
你没懂我的意思,现在我就是用的线程,就是遇到了问题
Jason_Mao1 2017-12-27
  • 打赏
  • 举报
回复
用委托 或者 线程 。如果要处理大数据 或者 要等待很长时间就用异步,这样可以缓解界面假死想象。希望能帮助到你。
yunqing1201 2017-12-27
  • 打赏
  • 举报
回复
直接用委托罗!!!
sakuragilyb 2017-12-27
  • 打赏
  • 举报
回复
回帖拿10分
twtyypmb123 2017-12-27
  • 打赏
  • 举报
回复
引用 1 楼 zhuo_wp 的回复:
this.BeginInvoke();
这句话如果this代表的是一个窗体或者控件的话,实际上这句话是让ui线程去操作传入的委托。因此如果传入的方法卡住,ui线程自然就会卡住,界面也就会卡住。 我猜是这样。
BeginInvoke没有问题,有问题的是Action
zhuowp 2017-12-27
  • 打赏
  • 举报
回复
this.BeginInvoke();
这句话如果this代表的是一个窗体或者控件的话,实际上这句话是让ui线程去操作传入的委托。因此如果传入的方法卡住,ui线程自然就会卡住,界面也就会卡住。 我猜是这样。

110,538

社区成员

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

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

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