c# - 不可预测的跨线程异常

标签 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 > 条件分支被执行。

下面的屏幕截图显示了现在引发异常的位置:

enter image description here

最佳答案

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

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

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

关于c# - 不可预测的跨线程异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18802663/

相关文章:

c# - LINQ 到 SQL : How to handle ambiguous column names when joining tables?

c# - Windows Phone 8 无法第二次调用 AudioVideoCaptureDevice

c# - C# WinformsErrorProvider

c# - 如何缩小按钮上的图像尺寸?

java - Thread.join() 和 Thread.interrupt() 不会停止线程

windows - 线程可以通过自己的线程 ID 调用 SuspendThread 吗?

c# - SQL 用户类型问题

c# - C#中如何删除不在栈顶的栈项

c# - 多个线程并发访问队列

java - Java的项目中使用scala的ParHashMap代替ConcurrentHashMap