我的应用程序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(),如果你有很多的交叉线程事件...
谢谢。
谢谢大家。
编辑:看起来BeginInvoke()
真的解决了这个问题。直到现在才会结冰。
发布于 2008-11-13 14:57:59
Invoke将一直等待,直到GUI线程处理完事件。如果希望它是异步的,请使用BeginInvoke()
发布于 2008-11-13 14:57:38
也许是死结?您是否确保在持有锁的同时不会触发事件?
你能在附加调试器的情况下看到这个吗?如果是这样的话,让它冻结,然后点击“暂停”按钮-看看UI线程在做什么。
请注意,如果您能够使用BeginInvoke而不是Invoke,生活就会更容易一些,因为它不会阻塞。
还要注意的是,您不需要“新的EventHandler”位--只要
Invoke((EventHandler) MyEventHandler, sender, e);
应该没问题。
发布于 2008-11-13 15:57:44
从这个问题中,我可以看到你不会得到任何可以立即解决这个问题的答案,因为他们中的大多数都需要你调试事件,而且这种情况发生得如此之少,以至于几乎不可能发生。因此,我建议您进行一些代码更改,以帮助您识别该领域的罪魁祸首。
我建议您创建一个静态类,它的唯一目的是处理所有的调用。我建议这个类有一个接受Control的方法,(在上面调用Invoke )一个Action (要调用的方法)和一个description (包含你需要知道的信息来识别这个方法以及它要做什么)。
在此方法的主体中,我建议您将此信息(方法、描述)排入队列并立即返回。
队列应该由单个线程提供服务,该线程从队列中弹出操作/消息对,在一对属性中记录当前时间和操作的描述,然后调用Action ()。操作返回时,描述和时间将被清除(您的DateTime可以为空,也可以将其设置为DateTime.Max)。请注意,由于所有调用都逐个编组到UI线程上,因此在这里由单个线程为队列提供服务不会造成任何损失。
现在,这就是我们要说的重点。我们的调用类应该有一个心跳System.Threading.Timer线程。这不应该是一个windows.forms.timer对象,因为它在UI线程上运行(当UI被阻塞时,它将被阻塞!)。
此计时器的任务是定期查看调用当前操作的时间。如果DateTime.Now - BeginTime > X,心跳计时器将决定此操作已被阻止。心跳计时器将记录(无论您如何记录)为该操作记录的描述。现在,您已经记录了锁定UI时发生的事情,并且可以更好地对其进行调试。
我知道这不能解决你的问题,但至少通过这样做,你可以对你被阻塞时发生的事情有一个很好的了解。
https://stackoverflow.com/questions/287142
复制相似问题