【发布时间】:2011-09-28 17:25:42
【问题描述】:
我正在开发一个多线程应用程序,该应用程序需要在运行时更新 Winforms 控件(A DataGridView)。为了防止对同一个共享资源的多次访问,我从如下锁结构入手:
if (DGV.Columns.Count >= DesiredColumnCount) return;
lock(DGV)
{
while (DGV.Columns.Count < DesiredColumnCount)
{
DGV.Columns.Add(newColumn);
}
}
然后我意识到,由于 DGV 是在 UI 线程上创建的,因此它必须是 .Invoke()'d。这会将代码更改为:
if (DGV.Columns.Count >= DesiredColumnCount) return;
lock(DGV)
{
DGV.Invoke(new MethodInvoker(() =>
{
while (DGV.Columns.Count < DesiredColumnCount)
{
DGV.Columns.Add(newColumn);
}
}
}
我的问题是:这不是多余的吗? lock 将阻塞工作线程,直到它拥有对DGV 的独占访问权,Invoke() 将阻塞工作线程,直到 UI 线程可以接收到调用请求并执行代码。我不能只使用Invoke()吗?
(这是主要问题。当然如果上面的代码中还有其他多线程的错误,请评论)
【问题讨论】:
-
你用什么来做“工作线程”?
-
你永远不应该阻塞 UI 线程。这适用于锁定以及 Control.Invoke。您应该摆脱锁定并将 Invoke 更改为 BeginInvoke。
-
@PeterRitchie 我不记得到底是什么开始了这个话题。可能是
new Thread().Start()或System.Threading.Timer.Elapsed。这段代码不会阻塞 UI 线程,它会阻塞工作线程。 BeginInvoke 不能盲目地替换 Invoke,因为它不会阻止调用者:我需要将调用排队,以确保它们不会因以错误的顺序执行而相互绊倒。这可能会通过减少阻塞工作线程所花费的时间来提高性能,但现在这是一个旧项目。
标签: c# .net winforms multithreading locking