[英]ManualResetEvent.WaitOne stuck the GUI
I have a Timer
that does several things 我有一个可以做几件事的
Timer
private System.Threading.Timer _xTimer = new System.Threading.Timer(new TimerCallback(XTimerHandler), null, 0, _xTimerPollingInterval);
private void XTimerHandler(object param)
{
//some code.
}
I have a function which stops the timer: 我有一个停止计时器的功能:
private void Stop()
{
//some code.
if (_xTimer != null)
{
ManualResetEvent timerDisposeHandler = new ManualResetEvent(false);
_xTimer.Dispose(timerDisposeHandler);
_dataProcessingTimer = null;
//wait for dispose end.
timerDisposeHandler.WaitOne();
}
}
Something very strange is going on! 发生了非常奇怪的事情!
Sometimes all the GUI hangs on timerDisposeHandler.WaitOne();
有时,所有的GUI都挂在
timerDisposeHandler.WaitOne();
(but only sometimes, and I could not see a pattern that repeats itself where it happens, it just dynamically) (但仅在某些情况下,并且我看不到会在发生这种情况时重复出现的模式,只是动态地重复出现)
Has anyone encountered a similar problem and solved it? 有没有人遇到过类似的问题并解决了?
Blocking the UI is effectively unsupported. 实际上不支持阻止UI。 While there are wait routines that are "supported" on the UI thread (which means they recognize there is a message pump and pump messages while you're waiting) it's not a good idea to do in general.
虽然有一些是在UI线程上“支持”等程序(这意味着他们承认有一个消息泵,而你等待泵消息)这不是一个好主意,一般做。
First, you're blocking the UI. 首先,您要阻止UI。 Yes, some message pumping can occur in certain circumstances, but do you really want the UI thread processing messages and waiting?
是的,在某些情况下可能会发生一些消息泵送,但是您真的想要UI线程处理消息并等待吗? Recipe for disaster if you're not really , really careful.
如果您不是真的 非常谨慎,请为灾难准备食谱。
Let's take a simple scenario. 让我们来看一个简单的场景。 Let's say that you've done your due diligence when writing your
Timer
callback (because you've chosen System.Threading.Timer
and not "System.Windows.Forms.Timer" which actually runs the Tick
event handler on the UI thread) and have chosen to marshal data back to the UI thread with Control.Invoke
(or Dispatcher.Invoke
with WPF, you haven't specified what type of Windows application you're talking about). 假设您在编写
Timer
回调时已经完成了尽职调查(因为您选择了System.Threading.Timer
而不是实际上在UI线程上运行Tick
事件处理程序的“ System.Windows.Forms.Timer”),并且已选择使用Control.Invoke
(或使用WPF的Dispatcher.Invoke
将数据Control.Invoke
送回UI线程,您尚未指定要使用的Windows应用程序类型。 Conceptually you've got a Stop
method that disposes the Timer
and stops callbacks. 从概念上讲,您有一个
Stop
方法,该方法处理Timer
并停止回调。 The Dispose
methods for Timer
are documented as saying that the callback can be called after Dispose
is called and thus a race condition, but also, there may be a callback being invoked at the same time you called Dispose
. 用于
Timer
的Dispose
方法的文档记录为,可以在调用Dispose
并因此形成竞争条件后调用该回调,但是在调用Dispose
同时,可能还会调用一个回调。 Both of these scenarios mean that between Dispose
and WaitOne
(or really just before WaitOne
) your Timer
callback may make that call to Invoke
. 这两种情况都意味着在
Dispose
和WaitOne
之间(或实际上在 WaitOne
之前 ),您的Timer
回调可能会调用Invoke
。 Invoke
is blocking and waits for the UI thread to process the message. Invoke
正在阻止,并等待UI线程处理消息。 But, if your Stop
method was invoked by something on the UI (ie a message) that means the message pump is blocked on WaitOne
. 但是,如果您的
Stop
方法是由UI上的某项(即消息)调用的,则意味着消息泵在WaitOne
上被阻止。 Deadlock . 死锁 。
You could, possibly , fix this simply by switching out Invoke with BeginInvoke . 您可以通过仅使用BeginInvoke切换Invoke来解决此问题。 But, you're still ultimately blocking the UI thread--keeping it, in most cases, from processing useful messages.
但是,您仍然最终仍会阻止UI线程-在大多数情况下,禁止它处理有用的消息。
Your question does not go into detail into what you're trying to do, so it's basically impossible to tell you exactly , or with any certainty, what to do to solve your problem. 你的问题不细讲到你想要做什么,所以基本上不可能确切地告诉你,或者有任何把握,怎样做才能解决您的问题。 Short answer: redesign so you don't have to wait.
简短答案:重新设计,因此您不必等待。 If you're still stuck on that, I'd suggest asking a different question outlining what you want to accomplish, what you've tried, and what to do to do it better.
如果您仍然坚持这样做,建议您提出一个不同的问题,概述您想要完成的工作,尝试过的工作以及如何做得更好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.