我有ManualResetEvent
。有一次,我使用WaitOne
等待该事件。令我惊讶的是,我在OnPaint
期间收到WaitOne
个事件。这种情况经常发生。
堆栈跟踪如下所示:
我知道WaitOne
会阻止当前线程,并且在事件触发之前不允许执行任何其他代码。
有人能解释一下这里发生了什么吗?
答案 0 :(得分:21)
这是设计的。 CLR尊重单线程公寓(STA)的合同。 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类不会进行这种抽运,这可能是另一种方式。虽然如果你这样做就会陷入僵局。
答案 1 :(得分:3)
我也看到了lock()
语句的这种行为。显然.net框架Thread类在等待UI线程上的锁时启动消息循环。这只是解释了发生了什么。原因可能是在使用旧的STA COM对象时防止死锁。我不知道有办法阻止这种情况。