ManualResetEvent.WaitOne卡住了GUI

时间:2014-10-01 06:37:39

标签: c# timer event-handling manualresetevent

我有Timer做了几件事

private System.Threading.Timer _xTimer = new System.Threading.Timer(new TimerCallback(XTimerHandler), null, 0, _xTimerPollingInterval);

private void XTimerHandler(object param)
{
    //some code.
}

我有一个停止计时器的功能:

private void Stop()
{
     //some code.
     if (_xTimer != null)
     {
        ManualResetEvent timerDisposeHandler = new ManualResetEvent(false);
        _xTimer.Dispose(timerDisposeHandler);
        _dataProcessingTimer = null;
        //wait for dispose end.
        timerDisposeHandler.WaitOne();

     }
}

发生了一些非常奇怪的事情!

有时候所有的GUI都挂在timerDisposeHandler.WaitOne();上(但只有有时候,我看不到一个模式会在它发生的地方重复,它只是动态的)

有没有人遇到类似问题并解决了?

1 个答案:

答案 0 :(得分:1)

实际上不支持阻止UI。虽然等待例程,但是#34;支持"在UI线程上(这意味着他们认识到有消息泵和消息,而你等待),一般来说这不是一个好主意。

首先,您要阻止用户界面。是的,在某些情况下可能会出现某些消息,但您真的希望UI线程处理消息等待吗?如果您不是真的真的小心,请为灾难准备。

让我们来看一个简单的场景。让我们说您在撰写Timer回调时已经完成了尽职调查(因为您选择了System.Threading.Timer而不是#34; System.Windows.Forms。 Timer"实际上在UI线程上运行Tick事件处理程序)并选择使用Control.Invoke(或Dispatcher.Invoke使用WPF将数据封送回UI线程,你没有&# 39; t指定了您正在谈论的Windows应用程序类型。从概念上讲,您已经获得Stop方法来处理Timer并停止回调。 Dispose的{​​{1}}方法被记录为可以在调用Timer之后调用回调,因此可以调用竞争条件,但也可能会调用回调函数你打电话给Dispose的时间。这两种情况都表示在DisposeDispose之间(或者只是之前 WaitOne),WaitOne回调可能会调用Timer 1}}。 Invoke正在阻塞并等待UI线程处理该消息。但是,如果您的Invoke方法被UI上的某些内容(即消息)调用,则意味着消息泵在Stop上被阻止。 死锁

可能可以通过使用 BeginInvoke 切换 Invoke 来解决此问题。但是,你仍然最终阻止了UI线程 - 在大多数情况下,保持它不会处理有用的消息。

您的问题没有详细说明您尝试做什么,所以基本上不可能告诉您完全,或者任何确定性,如何解决您的问题。简短的回答:重新设计,所以你不必等待。如果您仍然坚持这一点,我建议您提出一个不同的问题,概述您想要完成的内容,您尝试过的内容以及如何执行此操作更好。