我有一个 ManualResetEvent
。有一次,我使用 WaitOne
等待那个事件。令我惊讶的是,我在 WaitOne
中收到了一个 OnPaint
事件。这种情况也经常发生。
堆栈跟踪看起来像这样:
我知道 WaitOne
会阻塞当前线程,并且在事件触发之前不允许执行任何其他代码。
有人能解释一下这里发生了什么吗?
最佳答案
这是设计使然。 CLR 遵守单线程单元 (STA) 的契约(Contract)。 GUI 应用程序的主线程是 Windows 编程所要求的 STA,Main() 方法中的 [STAThread] 属性可确保这一点。
STA 线程的硬性规则是它必须泵送消息循环(如 Application.Run)并且永远不会阻塞。当后台线程使用任何 COM 单元线程对象时,阻塞 STA 线程很可能导致死锁。它们有很多,剪贴板和 WebBrowser 是您在 .NET 程序中会遇到的常见对象。还有许多不太明显的类,可作为 .NET 包装类使用。
当您使用 lock 语句或调用同步类的 Wait 方法时,CLR 会通过消息循环来确保阻塞不会导致死锁。或者 Thread.Join()。该消息循环调度 WM_PAINT 消息,导致 Paint 事件运行。
您需要重构您的程序以确保这不会导致问题。专注于完全不阻塞主线程非常重要。当您有 BackgroundWorker 类或 Control.BeginInvoke() 供您使用时,很少需要它。出于某种奇怪的原因,Mutex 类不进行这种泵送,这可能是另一种方式。尽管如果您这样做,死锁就潜伏在拐角处。
关于c# - 这怎么可能 : OnPaint processed while in WaitOne,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4540244/