Invoke()正在阻塞

时间:2008-11-13 14:55:07

标签: c# .net winforms .net-2.0

我的应用程序GUI有时会停止重绘。 有许多线程正在触发各种事件(如计时器或网络数据准备等)。还有很多控件正在订阅这些事件。因此,所有事件处理程序都会播放InvokeRequired / Invoke游戏。 现在我发现当GUI冻结时,很多线程都在等待Invoke()返回。看起来消息泵停止泵送。 处理程序看起来像这样:

private void MyEventHandler( object sender, EventArgs e ) {
    if ( InvokeRequired ) {
        Invoke( new EventHandler( MyEventHandler ), sender, e );
        return;
    }

    SetSomeStateVariable();
    Invalidate();
}

有什么想法吗?

解决方案:BeginInvoke()。看起来你应该总是使用BeginInvoke(),如果你有很多CrossThread-Events ......

感谢。

谢谢大家。

编辑:看起来BeginInvoke()真的解决了它。直到现在都没有冻结。

4 个答案:

答案 0 :(得分:27)

调用等待,直到在GUI线程中处理事件。如果您希望它是异步的,请使用BeginInvoke()

答案 1 :(得分:6)

也许死锁?您是否确保在持有锁时不会触发事件?

您是否可以在附加调试器的情况下看到这一点?如果是这样,请将其冻结,然后点击“暂停”按钮 - 并查看UI线程正在做什么。

请注意,如果您能够使用BeginInvoke而不是Invoke,生活会更容易,因为它不会阻止。

另请注意,您不需要“new EventHandler”位 - 只需

Invoke((EventHandler) MyEventHandler, sender, e);

应该没问题。

答案 2 :(得分:3)

通过观看这个问题,我可以看到你不会得到任何可以立即解决问题的答案,因为大多数答案都要求你调试事件,并且它很少发生,这几乎是不可能的。因此,我建议您进行一些代码更改,以帮助您确定该领域的罪魁祸首。

我建议您创建一个静态类,其唯一目的是处理所有的Invoke调用。我建议这个类有一个方法,它接受一个Control(调用Invoke)一个Action(要调用的方法)和一个描述(包含你需要知道的信息来识别方法及其含义要去做。)

在此方法的正文中,我建议您将此信息(方法,说明)排入队列并立即返回。

队列应由单个线程提供服务,该线程将动作/消息对从队列中弹出,在一对属性中记录当前时间和Action的描述,然后调用Action()。当Action返回时,将清除描述和时间(您的DateTime可以为空,或将其设置为DateTime.Max)。请注意,由于所有Invokes都会一次一个地编组到UI线程上,因此您不会通过单个线程在此处为队列服务而丢失任何内容。

现在,我们已经到了这一点。我们的Invoking类应该有一个心跳System.Threading.Timer线程。这不应该是一个windows.forms.timer对象,因为它在UI线程上运行(当ui被阻止时会被阻止!!!)。

此计时器的工作是定期查看当前Action被调用的时间。如果DateTime.Now - BeginTime> X,心跳计时器将决定此操作已被阻止。心跳计时器将记录(但是您记录)为该操作记录的描述。现在,您可以记录UI锁定时发生的情况,并可以更好地进行调试。

我知道这不是你问题的答案,但至少通过这样做,你可以很好地了解被阻止时发生的事情。

答案 3 :(得分:0)

已经提出了最可能的答案(死锁)。

模拟此行为的另一种方法是减少池线程和IO完成端口的数量;你有没有机会打电话给ThreadPool.SetMaxThreads(...)