BeginInvoke()调用延迟

时间:2013-11-13 20:17:35

标签: c# .net multithreading

我遇到Control.BeginInvoke()的问题,每次都不会发生。它看起来效果好5次左右,然后在那之后成为50/50的成功率。

发生的事情是我将在已创建并显示的控件上调用BeginInvoke(),并且不会立即在GUI线程上执行调用。调用线程 立即从BeginInvoke()返回并继续其业务。在控件上执行另一个BeginInvoke()之前,不会在GUI线程上执行该委托。然后就好像它意识到它有事可做,最后做到了。这可能超过10分钟。

代码

以下是执行不立即执行委托的BeginInvoke()的代码:

protected void DisplayPrompt(PromptData promptData)
{
    Debug.WriteLine(DateTime.Now + ": Entering DisplayPrompt: " + Thread.CurrentThread.Name);
    this.CurrentPrompt = promptData;

    if (this.InvokeRequired)
    {
        Debug.WriteLine(DateTime.Now + ": Before BeginInvoke of DisplayPrompt: " + Thread.CurrentThread.Name);
        this.BeginInvoke(new Action(() => this.DisplayPrompt(promptData)));
        Debug.WriteLine(DateTime.Now + ": After BeginInvoke of DisplayPrompt: " + Thread.CurrentThread.Name);
        return;
    }

    // The rest of the method goes here
}

通过消息泵启动调用方法的原因是以下代码执行时。在我厌倦了等待执行上面的委托之后执行此代码,然后按下最终调用ClearPrompt()的按钮。

protected void ClearPrompt()
{
    Debug.WriteLine(DateTime.Now + ": Entering ClearPrompt: " + Thread.CurrentThread.Name);
    this.CurrentPrompt = null;

    if (this.InvokeRequired)
    {
        Debug.WriteLine(DateTime.Now + ": Before BeginInvoke of ClearPrompt: " + Thread.CurrentThread.Name);
        this.BeginInvoke(new Action(() => this.ClearPrompt()));
        Debug.WriteLine(DateTime.Now + ": After BeginInvoke of ClearPrompt: " + Thread.CurrentThread.Name);
        return;
    }

    // The rest of the method goes here
}

最后,这是输出:

11/13/2013 1:16:49 PM: Entering DisplayPrompt: BatchStateMachine
11/13/2013 1:16:49 PM: Before BeginInvoke of DisplayPrompt: BatchStateMachine
11/13/2013 1:16:49 PM: After BeginInvoke of DisplayPrompt: BatchStateMachine
The thread 0x998 has exited with code 0 (0x0).
The thread 0x1174 has exited with code 0 (0x0).
11/13/2013 1:27:01 PM: Entering ClearPrompt: BatchStateMachine
11/13/2013 1:27:01 PM: Before BeginInvoke of ClearPrompt: BatchStateMachine
11/13/2013 1:27:01 PM: After BeginInvoke of ClearPrompt: BatchStateMachine
11/13/2013 1:27:01 PM: Entering DisplayPrompt: 
11/13/2013 1:27:01 PM: Entering ClearPrompt: 

这是Entering DisplayPrompt的第二个1:27:01 PM,这是GUI最终运行委托的地方。

问题: 所以我想问题是,什么可能导致BeginInvoke()出现这种延迟行为,我该怎么做才能更好地调试呢?

其他说明:

  1. 这些方法属于UserControl对象
  2. 的实例
  3. UserControl对象已经存在,并且在代码运行之前已经显示了几分钟,即控件句柄应该存在。
  4. 我之前已多次成功使用BeginInvoke()
  5. 在代表运行期间,GUI似乎完全响应。 GUI控件正在更新,我可以浏览应用程序等。
  6. 谢谢!

1 个答案:

答案 0 :(得分:0)

感谢Adam Maras的评论,我相信我已经找到了问题的根本原因。确实有大量的BeginInvoke()电话正在执行,但并不是很明显。我有另一个控件从后台线程接收大量更新。不足以导致问题正常,但问题是越来越多的控件实例都在接收更新并执行BeginInvoke()来更新GUI。

控件数量增加的原因是,当导航离开时,实例假定被销毁,并在返回到该视图时重新创建。但是,控件没有被销毁,因为它们已经从一个长期存在的类实例注册了更新事件,并且在从表单中删除控件时没有从事件中注销。这导致长期存在的类保存对所讨论的UserControl实例的引用,并且所有实例将继续处理事件并更新GUI,即使它们甚至不再可见。

因此即使GUI在某种程度上仍然响应,它也无法满足所有传入的异步调用。我读here SendMessage消息实际上没有像PostMessage消息那样被添加到消息队列中,而是直接由消息泵执行,并且具有比填充的消息队列更高的优先级。 PostMessage。因此,如果通过System.Windows.Forms.Timer事件处理正常的按钮点击和SendMessage事件,并且在消息队列上处理了BeginInvoke()个调用,我就会看到这种情况会如何发生。

感谢所有有用且快速的建议!谁知道我花了多长时间寻找它!