不可预知的跨线程异常

时间:2013-09-14 14:13:55

标签: c# .net 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);
    }
}

似乎InvokeRequired并不总是准确的。我尝试了BeginInvoke同样的结果。

编辑:即使我使用断点检查IsHandleCreatedInvokeRequired,它们也会设置为true,但条件的else分支会被执行。< / p>

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

enter image description here

1 个答案:

答案 0 :(得分:5)

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

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

当用户关闭表单时要小心,如果允许线程继续运行,原始代码的行为将非常糟糕。目前尚不清楚是否在创建表单窗口之前或关闭之后炸弹代码。您必须确保线程已停止或无法再调用ToOutput()。 this answer的主题。