C# 使用Control.Invoke()代替锁(Control)

C# 使用Control.Invoke()代替锁(Control),c#,.net,winforms,multithreading,locking,C#,.net,Winforms,Multithreading,Locking,我正在开发一个多线程应用程序,它需要在运行过程中更新Winforms控件(DataGridView)。为了防止对同一共享资源的多次访问,我从以下锁结构开始: if (DGV.Columns.Count >= DesiredColumnCount) return; lock(DGV) { while (DGV.Columns.Count < DesiredColumnCount) { DGV.Columns.Add(newColumn); } }

我正在开发一个多线程应用程序,它需要在运行过程中更新Winforms控件(DataGridView)。为了防止对同一共享资源的多次访问,我从以下锁结构开始:

if (DGV.Columns.Count >= DesiredColumnCount) return;
lock(DGV)
{
    while (DGV.Columns.Count < DesiredColumnCount)
    {
        DGV.Columns.Add(newColumn);
    }
}
我的问题是:这不是多余的吗?
lock
将阻止工作线程,直到它以独占方式访问
DGV
,而
Invoke()
将阻止工作线程,直到UI线程能够拾取调用请求并执行代码。我不能只使用
Invoke()


(这是主要问题。当然,如果上述代码中存在任何其他多线程问题,请予以评论)

这有点多余,调用
调用将把操作“分派”到UI线程。每个后续的
Invoke
调用都将以串行方式进行调度,因此实际上不需要执行任何锁定


您可以考虑使用<代码> SncReunk> <代码>,而不是<代码>调用> <代码>命令,以防止工作线程被阻塞,但再次,将“串行”完成,因此不必担心锁定。

谢谢帖子,但我很困惑。Skeet先生在()中说Control.Invoke在UI线程上执行并等待完成。是的,他说的是BeginInvoke()。没关系,你也不需要锁。所有代码都在同一个线程上运行,因此不需要保护数据。不仅锁是冗余的,而且死锁正在等待发生。如果在调用
Invoke
期间调用的某个代码试图获取锁,则您会被卡住,因为您的线程正在持有锁,等待
Invoke
在UI线程上完成,而UI线程正在等待获取锁。@Nathan抱歉,这是一个措词不当的解释,我重新编写了我的答案。你用什么作为“工作线程”?你永远不应该阻止UI线程。这适用于lock和Control.Invoke。你应该去掉锁,将Invoke改为BeginInvoke。@PeterRitchie我不记得线程的确切开始。它可能是
new Thread().Start()
System.Threading.Timer.appead
。此代码不会阻止UI线程,它会阻止工作线程。不能盲目地用BeginInvoke代替Invoke,因为它不会阻止调用者:我需要对调用进行排队,以确保它们不会因执行顺序错误而相互绊倒。这可能会通过减少阻塞工作线程所花费的时间来提高性能,但到目前为止,这是一个旧项目。
if (DGV.Columns.Count >= DesiredColumnCount) return;
lock(DGV)
{
    DGV.Invoke(new MethodInvoker(() =>
        {
            while (DGV.Columns.Count < DesiredColumnCount)
            {
                DGV.Columns.Add(newColumn);
            }
        }
}