ManualResetEvent.WaitOne stuck the GUI

本文关键字:GUI the stuck WaitOne ManualResetEvent | 更新日期: 2023-09-27 18:25:13

我有一个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();上(但有时只有,我看不到在发生这种情况的地方重复的模式,它只是动态的)

有人遇到过类似的问题并解决了吗?

ManualResetEvent.WaitOne stuck the GUI

实际上不支持阻塞UI。虽然UI线程上"支持"有等待例程(这意味着它们识别出有一个消息泵,并在等待时泵送消息),但通常这样做不是一个好主意。

首先,您正在阻塞UI。是的,某些消息泵送在某些情况下可能会发生,但您真的希望UI线程处理消息等待吗?如果你真的不小心,就会造成灾难。

让我们来看一个简单的场景。假设您在编写Timer回调时已经进行了尽职调查(因为您选择了System.Threading.Timer,而不是"System.Windows.Forms.Timer",它实际上在UI线程上运行Tick事件处理程序),并选择使用Control.Invoke将数据封送回UI线程(或使用WPF的Dispatcher.Invoke,您还没有指定所说的Windows应用程序的类型)。从概念上讲,您得到了一个Stop方法,该方法处理Timer并停止回调。TimerDispose方法被记录为,可以在调用Dispose之后调用回调,因此这是一个竞争条件,但也可能在调用Dispose的同时调用回调。这两种情况都意味着,在DisposeWaitOne之间(或者实际上只是在WaitOne之前的),Timer回调可能会对Invoke进行调用。CCD_ 19正在阻塞并等待UI线程处理该消息。但是,如果您的Stop方法被UI上的某些东西(即消息)调用,则意味着消息泵在WaitOne上被阻止死锁

可以,可能,通过用BeginInvoke切换出Invoke来解决此问题。但是,您最终仍然会阻塞UI线程——在大多数情况下,它无法处理有用的消息。

你的问题并没有详细说明你试图做什么,所以基本上不可能准确地告诉你,也不可能确切地告诉你该怎么解决你的问题。简短的回答是:重新设计,这样你就不必等待了。如果你仍然坚持这一点,我建议问一个不同的问题,概述你想完成什么,你已经尝试了什么,以及如何做才能做得更好。