我有一个winforms应用程序。在开发模式下,从Visual Studio .NET 2003进行调试时(是的,我知道它已经过时,但这是一个遗留项目),当我尝试打开一个新表单时出现此错误。为了打开一个新表单,我得到一个表单实例,然后我调用ShowDialog()方法,例如:
frmTest test = new frmTest(here my parameters);
test.ShowDialog();
如果我按F11(步入)调试它没有崩溃,但如果在我实例化表单的行中我按F10进入下一行,即test.ShowDialog(),然后它崩溃显示这个错误。
完整的消息错误是:
“发生了'System.ApplicationException'类型的未处理异常 在System.drawing.dll中。附加信息:试图进行 释放不属于过程的互斥“
我翻译了最后一部分:附加信息......因为它出现在西班牙语中。
我使用参数及其构造函数实例化的表单包括初始化一些变量,例如:
public frmTest(string param1, string param2)
{
InitializeComponent();
this.param1 = param1;
this.param2 = param2;
}
private void frmTest_Load(object sender, EventArgs e)
{
// here I call a remote webservice asynchronously.
}
我的表格“frmTest”还有四个图片框,一个标签和一个按钮。其中三个图片框包含一个png图像(它是在设计时通过Image属性分配的),最后一个图片框包含一个动画gif,也是通过Image属性在设计时加载的。可能由于这些图像而发生错误?
答案 0 :(得分:1)
TL; DR::您的Web请求处理程序将在其他线程上执行。确保您不要在该处理程序中执行任何不是线程安全的操作。您可以使用
Invoke
将回调处理程序的代码发送到主线程。
这里的问题几乎可以肯定隐藏在异步调用的缺失细节中。
// here I call a remote webservice asynchronously.
异步有点模糊,无法确定正在发生什么 ,但是您使用的异步机制很有可能执行了<从主UI线程在另一个线程上strong>回调。
这在.NET模型中很常见。 .NET模型中的异步I / O使用线程池中的线程通过I/O Completion Ports (IOCP)处理I / O。这意味着当Socket.BeginReceive
或WebRequest.BeginGetResponse
之类的调用(或内部使用类似技术的任何.NET异步Web请求)完成时,回调将在线程池中的线程上执行, 不是主线程 。这可能使您感到惊讶,因为您没有主动创建另一个线程。您刚刚参与了异步调用。
您必须非常小心在Web请求的回调中执行的操作,因为除主UI线程以外,任何线程都不允许进行许多用户界面/ Windows窗体操作。同样,可能不是UI本身引起了您的问题,您可能刚刚访问了一些线程安全的资源或对象。如果您不小心使用多线程,那么许多看似无害的事情都可能导致崩溃或异常。
如果有疑问,请尽早在回调中调度(也称为Invoke
)处理程序中的代码,使其在主线程上运行。
执行此操作的常见模式如下所示。
假设您拨打了这样的电话:
IAsyncResult result = (IAsyncResult myHttpWebRequest.BeginGetResponse(
new AsyncCallback(RespoCallback), myRequestState);
处理程序可以这样设置:
private static void RespCallback(IAsyncResult asynchronousResult)
{
// THIS IS NOT GOING TO WORK BECAUSE WE ARE ON THE WRONG THREAD. e.g.:
this.label1.Text = "OK"; // BOOM! :(
}
相反,将所有必要的处理分派回主线程。
private static void RespCallback(IAsyncResult asynchronousResult)
{
this.Invoke((MethodInvoker) delegate {
// This block of code will run on the main thread.
// It is safe to do UI things now. e.g.:
this.label1.Text = "OK"; // HOORAY! :)
});
}
我不建议将此作为最佳常规做法。我不是是要立即将所有处理程序分派回主线程。一种尺寸不不能全部适合。您应该真正查看在处理程序中执行的操作的特定细节,并确保您未执行特定于线程的操作。但是我 am 说,如果您没有关于异步处理程序正在做什么的任何解释,则该问题很可能可以通过主线程上的invoking处理程序代码来解决。
注意:当然,要解决此技术的问题,它要求您的主线程正在运行。如果您使用this example中的一种(不良)技术来阻塞主线程,那么您将不得不重新设计应用程序的一部分。这是一些需要大量返工的示例:
// Start the asynchronous request.
IAsyncResult result=
(IAsyncResult) myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback),myRequestState);
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
ThreadPool.RegisterWaitForSingleObject (result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), myHttpWebRequest, DefaultTimeout, true);
// The response came in the allowed time. The work processing will happen in the
// callback function.
allDone.WaitOne(); // *** DANGER: This blocks the main thread, the IO thread
// won't be able to dispatch any work to it via `invoke`
注意到WaitOne
通话吗?这阻止了正在执行的线程的执行。如果此代码在主线程上执行,则主线程将被阻塞,直到WebRequest完成。您必须重新设计,以便不阻塞主线程(我的建议),或者更仔细地检查回调处理程序以了解其作用与其他线程发生冲突的原因。
答案 1 :(得分:0)
框架本身不会抛出应用程序异常:what-is-applicationexception-for-in-net;问题应该在你没有框架的代码中。另外一定要检查&#34; InvokeRequired&#34;在执行操作之前的属性,如果是,则使用&#34; Invoke&#34;运行方法。方法。可以检查c-sharp-cross-thread-call-problem。
答案 2 :(得分:0)
可能是异步调用正在尝试访问UI线程。
确保您没有使用诸如TextBox.Text
之类的控件属性。如果是这样,则只需将其值传递给异步调用,或在调用之前将其存储在类变量中。
此外,在异步调用中,您无法为该属性分配值。请改用Invoke()
。
答案 3 :(得分:-1)
尝试添加异常断点,VS将在导致异常的指令处停止。实际的堆栈跟踪可能会有所帮助。
您是否尝试过关闭VS的局部变量监视窗口?也许它正在为UI组件上的您评估一些东西,其中访问线程应等于UI组件的所有者线程!