“跨线程操作无效”不会杀死WinForms应用程序(应该) [英] 'Cross-thread operation not valid' does not kill WinForms application (and it should)

查看:141
本文介绍了“跨线程操作无效”不会杀死WinForms应用程序(应该)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:这里是一个MSDN文章如何到:对Windows窗体控件进行线程安全调用。它指出:


当您以某种方式访问​​控件
时,.NET Framework可帮助您检测
不是线程安全的
当你在调试器中运行你的应用程序
,而另一个
的线程比创建控件
的线程尝试调用该控件时,
调试器引发一个
InvalidOperationException与
消息,控制名称
从除了
线程之外的线程访问。




调试期间,在
的情况下,在运行时,此异常可靠地发生。


我以前的经验是在运行时抛出异常。



感谢Spence指出我正确的方向。

$ b $我在WinForms应用程序中有一个很常见的错误:后台线程直接访问UI控件,而不是使用Control.BeginInvoke()。



我的问题如下:我看到InvalidOperationException跨线程操作无效:控制'uxCheckStatus'从除了创建线程之外的线程。在调试器的背景线程上,但是在WinForms内部的某个地方被吞下来。



我希望它可以杀死后台线程和整个应用程序。



此外,触发它的代码 uxCheckStatus.Text =success; 有时会在/之后执行异常,即标签文本读取'成功'!我基本上输了其他任何人遇到这种情况?



我用全新的WinForms解决方案将其复制到1个按钮,两者都使用ThreadPool和Thread for evil background thread。



如果我在后台线程上抛出一个新的InvalidOperationException(),它会杀死应用程序。所以我唯一的猜测是WinForms处理这个特定的例外,但是我找不到网络上这个行为的引用。



我运行.NET 3.5 VS VS。 / p>

解决方案

这是设计。这是一个编码错误,而不是运行时错误。 Winforms的开发人员决定从.Net 2开始,他们将实施代码来检查交叉线程代码,然后启动MDA。 MDA不是一个例外,它是对设计不良的代码进行检查。



此外,当代码处于释放模式时,MDA不会触发,它只会随机失败,MDA将帮助您进行测试,而不是在发布过程中。



我假设您正在重写一个写入不当的应用程序来调用线程,你希望这个例外可以捕捉到你,我有一个建议:



更新您的事件处理程序的GUI东西,如下所示:

  public void button_clicked_handler(object sender,EventArgs e)
{
if(this.InvokeRequired)
{
this.Invoke(delegateToThisMethod)
}
else
{
//执行方法
}
pre>

此模式将捕获所有的方法,并使其无缝跨线操作。如果线程直接访问代码,这有点难度。您可以通过重命名控件,然后为控件创建属性来解决此问题,然后可以在其中应用调用模式。我不得不这样做,以排除一些非常时髦的十字线东西之前。



祝你好运;)



编辑:
只是想澄清一点,检查当前线程和Win Forms线程的同步上下文是一项昂贵的操作。因此,他们实现MDA的原因是让您在调试中找到它,但是您的发布模式代码在每次访问每个Windows窗体控件的每个属性或方法时都不会减慢。


Update: here is an MSDN article How to: Make Thread-Safe Calls to Windows Forms Controls. It states:

The .NET Framework helps you detect when you are accessing your controls in a manner that is not thread safe. When you are running your application in the debugger, and a thread other than the one which created a control tries to call that control, the debugger raises an InvalidOperationException with the message, "Control control name accessed from a thread other than the thread it was created on."

This exception occurs reliably during debugging and, under some circumstances, at run time.

My previous experience was that the exception was thrown at run time, too.

Thanks to Spence for pointing me in the right direction.


I have a pretty common error in WinForms app: background thread accessing UI controls directly instead of using Control.BeginInvoke().

My problem is the following: I see the InvalidOperationException "Cross-thread operation not valid: Control 'uxCheckStatus' accessed from a thread other than the thread it was created on." in debugger on background thread, but then it is swallowed somewhere in WinForms internals.

I expect it to kill the background thread and entire application.

Moreover, the code that is triggering it uxCheckStatus.Text = "success"; sometimes gets executed during/after exception is thrown i.e. label text reads 'success'! I'm basically lost. Anyone else experiencing this behavior?

I reproduce it on completely new WinForms solution with 1 button, both using ThreadPool and Thread for evil background thread.

If I throw a new InvalidOperationException() on background thread, it does kill the application. So my only guess is that WinForms handles this specific exception somewhere, but I cannot find references to this behavior on the web.

I run .NET 3.5, VS 2008.

解决方案

THis is by design. This is a coding error, not a runtime error. THe developers of Winforms decided that from .Net 2, they would implement code to check for the cross thread code and then fire an MDA. The MDA isn't an exception though, it's a check for badly designed code.

Additionally the MDA doesn't fire when your code is in release mode, it will just randomly fail every so often, the MDA is to help you at test, not during release.

I'm assuming that you are rewriting a badly written application to invoke onto the threads and you were hoping that the exceptions would catch for you, I have a suggestion:

Update your event handlers for GUI stuff to look like so:

public void button_clicked_handler(object sender, EventArgs e)
{
   if(this.InvokeRequired)
{   
   this.Invoke(delegateToThisMethod)
}
else
{
   //perform method
}

This pattern will catch all your methods and make it seamless for cross thread ops. If the threads are directly accessing code, this is a little tougher. You can get around this by renaming a control, then creating a property to the control, where you can then apply the invoke pattern to it. I've had to do this to troubleshoot some very funky cross thread stuff before.

Good luck ;)

EDIT: Just wanted to clarify that checking the synchronisation context of the current thread and the Win Forms thread is a costly operation. Thus the reason they implemented the MDA is so that you find it in debug but that your release mode code isn't slowed down on EVERY access to EVERY property or method of a windows forms control.

这篇关于“跨线程操作无效”不会杀死WinForms应用程序(应该)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆