Invoke()正在阻塞

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

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

有任何想法吗?

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

谢谢。

谢谢大家。

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

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

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

您是否可以通过附加调试器来查看此内容? 如果是这样,请将其冻结,然后点击“暂停”按钮 – 并查看UI线程正在做什么。

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

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

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

应该没事。

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

我建议你创建一个静态类,其唯一目的是处理所有的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锁定时发生的情况,并可以更好地调试它。

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

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

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