【问题标题】:cross-thread operation even when executing on UI thread即使在 UI 线程上执行时也可以进行跨线程操作
【发布时间】:2010-07-23 00:35:37
【问题描述】:

我有一个函数可以将控件添加到父控件,该控件是从与创建控件的线程不同的线程调用的。事情是这样的:

1        delegate void AddControlToParentDelegate(Control child, Control parent);
2        private void addControlToParent(Control child, Control parent) {
3        if (parent.InvokeRequired) {
4            AddControlToParentDelegate d = new  AddControlToParentDelegate(addControlToParent);
5            this.Invoke(d, new object[] { child, parent });
6            } else {
7                parent.Controls.Add(child);
8            }
9        }
10    }

parent.InvokeRequiredchild.InvokeRequired 都为 TRUE 之前,这可以正常工作。然后,一旦执行了第 5 行(现在调用了委托d,并且该函数应该在 UI 线程上运行。(对吗?))第 7 行的child 会引发跨线程操作无效异常。为什么是这样?它不是已经在它创建的线程上运行了吗?

我设法通过添加一个额外的(child.InvokeRequired) 检查来解决这个问题:

delegate void AddControlToParentDelegate(Control child, Control parent);
private void addControlToParent(Control child, Control parent) {
    if (parent.InvokeRequired) {
        AddControlToParentDelegate d = new AddControlToParentDelegate(addControlToParent);
        this.Invoke(d, new object[] { child, parent });
    } else {
        if (child.InvokeRequired) {
            this.Invoke(new MethodInvoker(delegate() {
            parent.Controls.Add(child);
            }));
        } else {
            parent.Controls.Add(child);
        }
    }
}

但这似乎非常骇人听闻且不必要。这是这样做的方法吗?还是我完全错过了公共汽车?

【问题讨论】:

    标签: c# winforms invoke multithreading


    【解决方案1】:

    请注意,当控件没有窗口句柄时,InvokeRequired 是不可靠的。几乎可以肯定的是,新创建的子控件还没有父控件,这在您的“固定”代码中似乎就是这种情况。

    查看 Ivan Krivyakov 的详细分析:http://www.ikriv.com/en/prog/info/dotnet/MysteriousHang.html

    【讨论】:

    • 此外,使用InvokeRequired的设计更易于维护。我建议将Task 调度到ui 线程或使用BackgroundWorker.ReportProgress,这两者都是独立于平台的解决方案(即不绑定到Windows 窗体)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    相关资源
    最近更新 更多