我遇到了一些我完全不理解的东西。
在我的应用程序中,我有多个线程都向共享集合中添加(和删除)项目(使用共享锁)。
UI线程使用计时器,在每次计时器间隔内使用集合来更新其UI界面。
由于我们不希望UI线程长时间持有锁并阻塞其他线程,所以我们的做法是,首先获取锁,复制集合,释放锁,然后在我们的副本上工作。 代码看起来像这样:
由于我们不希望UI线程长时间持有锁并阻塞其他线程,所以我们的做法是,首先获取锁,复制集合,释放锁,然后在我们的副本上工作。 代码看起来像这样:
public void GUIRefresh()
{
///...
List<Item> tmpList;
lock (Locker)
{
tmpList = SharedList.ToList();
}
// Update the datagrid using the tmp list.
}
尽管它能正常工作,但我们注意到应用程序有时会变慢,当我们成功捕获堆栈跟踪时,发现了以下信息:
....
at System.Windows.Forms.DataGrid.OnPaint(PaintEventArgs pe)
at MyDataGrid.OnPaint(PaintEventArgs pe)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Threading.Monitor.Enter(Object obj)
at MyApplication.GuiRefresh()
at System.Windows.Forms.Timer.OnTick(EventArgs e)
at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
....
注意,进入锁(Monitor.Enter)后会跟着 NativeWindow.Callback,从而导致 OnPaint 被调用。
这怎么可能?UI 线程是否被劫持以检查其消息队列?这有意义吗?还是说这里有其他原因?
有没有办法避免这种情况?我不希望在锁内调用 OnPaint。
谢谢。
lock
中的OnPaint
(我的堆栈跟踪说“由托管到本机转换”而不是“Monitor.Enter()
”),这是在一个OnScroll
处理程序中。我认为缓慢的原因是OnScroll
处理程序未完成导致某些魔法(例如,缓存值?)丢失,从而导致OnPaint
运行缓慢。 - binki