不可预知的跨线程异常

Lee*_*Lee 2 .net c# multithreading thread-safety

在执行我的win表单应用程序时,我将获得一个跨线程异常似乎是一个随机的机会.以下是我试图管理它的方法:

private void ToOutput(string s)
{
    if (!this.IsHandleCreated)
        this.CreateHandle();

    if (FormOutputArea.InvokeRequired)
    {
        FormOutputArea.Invoke(new Action(delegate ()
        {
            FormOutputArea.AppendText(s + Environment.NewLine);
        }));
    }
    else
    {
        FormOutputArea.AppendText(s + Environment.NewLine);
    }
}
Run Code Online (Sandbox Code Playgroud)

它似乎InvokeRequired并不总是准确的.我尝试BeginInvoke了相同的结果.

编辑:即使我检查IsHandleCreatedInvokeRequired使用断点,它们也设置为true,但else条件的分支仍然执行.

这是一个截图,显示现在抛出异常的位置:

在此输入图像描述

Han*_*ant 5

将CreateHandle()和InvokeRequired放在同一个方法中是根本错误的.当尚未创建句柄时,这将爆炸,您将在错误的线程上创建本机窗口.子控件的窗口必须由拥有该窗体的同一个线程拥有,并且该线程必须泵送一个消息循环(Application.Run).

简单的解决方法是确保在创建表单窗口之前不会启动线程.这也将创建嵌入在该表单中的所有控件的窗口.最早发生的是表单的Load事件.此时,您可以信任InvokeRequired是准确的.

当用户关闭表单时要小心麻烦,如果允许线程继续运行,原始代码将表现得很差.目前尚不清楚是否在创建表单窗口之前或关闭之后炸弹代码.您必须确保线程已停止或无法再调用ToOutput().这个答案的主题.