了解 InvalidAsynchronousStateException 的发生
何时抛出 InvalidAsynchronousStateException?
我有以下代码:
control.InvokeRequired ? 控制.调用(表达式): 表达式();
在某些随机情况下,我得到 InvalidAsynchronousStateException 并且我的应用程序挂起,经过一些阅读后,似乎在创建 control
的线程完成时会抛出此异常。这是正确的吗?如果是这样,情况似乎并非如此,除非有什么原因导致我的应用程序崩溃并且此异常只是一个结果?这可能吗?
System.ComponentModel.InvalidAsynchronousStateException:调用该方法时发生错误。目标线程不再存在。 在 System.Windows.Forms.Control.WaitForWaitHandle(WaitHandle waitHandle) 在 System.Windows.Forms.Control.MarshaledInvoke(控制调用方、委托方法、Object[] args、布尔同步) 在 System.Windows.Forms.Control.Invoke(委托方法,Object[] args) 在 System.Windows.Forms.Control.Invoke(委托方法) 在 c:\Optimus\Desktop\Framework\Spring\Aspects\UIThreadInterceptor.cs 中的 Optimus.Desktop.Framework.Spring.Aspects.UIThreadInterceptor.Invoke(IMethodInspiration 调用):第 22 行 在 Spring.Aop.Framework.AbstractMethodInitation.Proceed() 在 Spring.Aop.Framework.DynamicProxy.AdvisedProxy.Invoke(对象代理,对象目标,类型 targetType,MethodInfo targetMethod,MethodInfo proxyMethod,Object[] args,IList 拦截器) 在InheritanceAopProxy_4fda07e8828744839065a154b30915ee.Dispose(布尔处置) 在 System.ComponentModel.Component.Finalize()
顺便说一句,我已经检查了这个答案,但没有澄清我的疑问 -> 检查控制是否需要调用的函数中的 InvalidAsynchronousStateException< /a>
When does InvalidAsynchronousStateException get thrown?
I have the following piece of code:
control.InvokeRequired ?
control.Invoke(expression) :
expression();
In some random cases I get InvalidAsynchronousStateException and my application hangs, after doing some reading it seems to be that this exception will be thrown when the thread where the control
was created finished. Is this correct? If so, this doesn't seem to be the case, unless something is making my application crash and this exception is just a consequence? is this possible?
System.ComponentModel.InvalidAsynchronousStateException: An error occurred invoking the method. The destination thread no longer exists.
at System.Windows.Forms.Control.WaitForWaitHandle(WaitHandle waitHandle)
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.Invoke(Delegate method)
at Optimus.Desktop.Framework.Spring.Aspects.UIThreadInterceptor.Invoke(IMethodInvocation invocation) in c:\Optimus\Desktop\Framework\Spring\Aspects\UIThreadInterceptor.cs:line 22
at Spring.Aop.Framework.AbstractMethodInvocation.Proceed()
at Spring.Aop.Framework.DynamicProxy.AdvisedProxy.Invoke(Object proxy, Object target, Type targetType, MethodInfo targetMethod, MethodInfo proxyMethod, Object[] args, IList interceptors)
at InheritanceAopProxy_4fda07e8828744839065a154b30915ee.Dispose(Boolean disposing)
at System.ComponentModel.Component.Finalize()
btw, I've checked this answer and didn't clarify my doubt -> InvalidAsynchronousStateException in function that checks if invoke is required for control
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
通常,当后台线程在 UI 线程已退出后尝试调用 UI 线程时,会发生这种情况。您是否有机会尝试在各自的线程中运行不同的表单,或者您是否从非 UI 线程 Show() 表单,或者在显示表单之前 Invoke() 到表单?
背景如下:
1)每个控件(包括Forms)都有一个句柄。这用于将控件绑定回底层 Windows GDI 对象。
2) 创建控件本身时通常不会创建控件的句柄。当控件第一次被 Show()n 时,句柄被创建。
3) 当调用一个控件时,.NET API 尝试使用它的句柄来定位该控件的 UI 线程。 如果表单尚未显示,则 CURRENT THREAD(调用线程)将被指定为 UI 线程。
4) 控件的 UI 线程预计会运行一个消息循环来处理该控件(当您这样做时会自动发生,例如,Application.Run(someForm);
5) 因此,常见的错误是您创建了一个表单 F 、 Invoke() 或 BeginInvoke() 从临时线程或线程池线程调用它,这会创建表单的句柄,因此被分配为表单的 UI 线程。然后后台线程退出,或者被线程池终止,或者根本无法运行消息循环,因为它不知道它已被指定为 UI 线程。随后,对该表单的任何调用都会失败并出现此异常。抛出异常只是因为表单分配的“UI 线程”没有运行消息循环。
请参阅 Ivan 的帖子,了解如何发生这种情况的详细分析:http://www .ikriv.com/en/prog/info/dotnet/MysteriousHang.html
Usually this occurs when a background thread is attempting to invoke to a UI thread after the UI thread has already exited. Do you by any chance attempt to run different forms each in their own thread, or do you Show() forms from a non-UI thread, or Invoke() to a form before it is shown?
The background is as follows:
1) Every control (including Forms) has a handle. This is used to tie the control back to the underlying windows GDI objects.
2) The control's handle is usually not created when the control itself is created. The handle is created when the control is Show()n for the first time.
3) When Invoking to a control, the .NET API attempts to locate the control's UI thread using it's handle. If the form has not yet been shown, the CURRENT THREAD (the invoking thread) will be assigned as the UI thread.
4) The UI thread for a control is expected to run a message loop for handling that control (which happens automatically when you do, for instance, Application.Run(someForm);
5) So the common mistake is that you create a form F, Invoke() or BeginInvoke() to it from a temporary or threadpool thread, which creates the form's handle and is therefore assigned as the form's UI thread. Then the background thread exits, or is terminated by the threadpool, or simply fails to run a message loop, since it is not aware that it has been designated a UI thread. Subsequently, any invocations to that form fail with this exception. The exception is thrown simply because the form's assigned 'UI thread' is not running a message loop.
See Ivan's post for a detailed analysis of how this happens: http://www.ikriv.com/en/prog/info/dotnet/MysteriousHang.html
我最近遇到了同样的问题。我的表单包含几个不可见的用户控件,这些控件可能需要在应用程序生命周期的后期出现。有时,这些请求来自后台线程。
问题是,即使我将
control.Visible = true
包含在control.Invoke
中,该控件实际上还是分配给了后台线程(如 Chris 的观点 #3 中所述) ) 而不是表单的主 UI 线程。对我来说,一个简单的解决方法是在创建父窗体期间调用一次IWin32Window.Handle
属性(例如从窗体的 Load 事件),这可确保控件是在主 UI 线程中创建,但不使其可见。I've been faced to the same issue recently. My form contains several invisible user controls that may be required to appear later in the life cycle of the application. Sometimes, those requests come from background threads.
The problem was that even if I enclose
control.Visible = true
inside acontrol.Invoke
, the control was actually assigned to the background thread (as mentioned in Chris's point #3) instead of the form's main UI thread. A simple workaround for me was to call once theIWin32Window.Handle
property during the creation of the parent form (for instance from the form's Load event) This ensures that the control is created in main UI thread without making it visible.正如其他人正确地表明的那样,当 UI 组件被释放或完成(返回),而不同的线程仍在同一 UI 组件上调用代码时,就会发生这种情况。
当用户关闭已由不同线程更新的窗口(表单)时,通常会发生这种情况,并且当更新频率较高时这种情况更为普遍(因为当用户关闭表单时发生不完整调用的可能性很高) 。
这可以通过以下方式妥善处理:
下面的示例显示如何妥善处理最常见的情况(当表单在更新时关闭时)。
该示例来自一个简单的表单,该表单具有一个列表框,该列表框通过公共方法 (AddItem(string)) 从外部线程更新。
标志
调用代码
拦截和管理表单关闭事件
您可以通过公开一个方法或属性来进一步扩展此功能,让用户(其他线程)知道表单正在关闭,以便调用者可以优雅地处理这种情况。
下面的示例显示了新属性 (ShuttingDown) 如何允许调用者在用户关闭显示表单时正确处理其流程。
表单上的新标志
来电者现在可以检测问题
您可以从此处阅读更多信息并下载示例项目:http://www.ilearnttoday.com/c-sharp-the-destination-thread-no-longer-exists
As others have correctly shown this happens when a UI component is disposed or is completed (return) while a different thread is still invoking code on the same UI component.
This usually happens when a user closes a window (a form) that has been updated by a different thread and this is more prevalent when the update frequency is high (because the chance of having an incomplete invoke when the user closes the form is high).
This can be gracefully handled by:
Below example shows how to gracefully handle the most common scenario (when a form is closed while it's been updated).
The example is from a simple form that has a listbox that is updated from an outside thread via a public method (AddItem(string)).
Flags
Invoking code
Intercepting and managing form closing event
You can further extend this by exposing a method or a property that lets the users (other threads) know that the form is shutting down so that the callers can gracefully handle the situation.
Example below shows how a new property (ShuttingDown) allows a caller to handle its flow correctly if a user closes the display form.
New flag on form
Caller now can detect the problem
You can read more and download the sample project from here: http://www.ilearnttoday.com/c-sharp-the-destination-thread-no-longer-exists