【问题标题】:Unpredictable cross-thread exception不可预知的跨线程异常
【发布时间】:2023-03-19 04:00:01
【问题描述】:

在执行我的 win forms 应用程序时,我会遇到一个跨线程异常,这似乎是一个随机的机会。以下是我尝试管理它的方式:

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 分支仍会执行。

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

【问题讨论】:

  • 您可能想查看以下内容:stackoverflow.com/questions/808867/…
  • 即使检查控制句柄是否已创建也无济于事。我很困惑为什么连续运行五次(〜20%的机会)时抛出一次线程异常。
  • 即使当我使用断点检查 IsHandleCreated 和 InvokeRequired 时,它们也会设置为 true,但条件的 else 分支会被执行。 你能告诉这段代码你在这个中尝试了什么吗?
  • this 在这里指的是什么?
  • 我希望this 会引用此方法所在的类。我最初使用FormOutputArea.IsHandleCreated 但是当表单区域对象没有CreateHandle 方法时将其更改为this,无济于事。

标签: c# .net multithreading thread-safety


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢汉斯,我想我已经解决了这个问题。我在表单的构造函数中初始化并启动了后台线程。我已将这些移至 _Load 事件,该事件似乎已对其进行了排序!幸好问题比我预想的要简单。
猜你喜欢
  • 1970-01-01
  • 2011-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多