跨线程操作

3

有人能告诉我这个函数中的if和else语句有什么关系吗?我正在将来自另一个线程的文本显示到GUI线程中。执行的顺序或方式是什么?else语句是否必要?

delegate void SetTextCallback(string text);

    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.textBox7.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.textBox7.Text = text;
        }
    }

如果没有else,程序很可能会崩溃,因为您无法从外部线程更改GUI。既然您需要更改GUI,那么您应该使用Invoke方法。如果没有else,外部线程将在调用方法后尝试立即更改GUI(导致我之前提到的崩溃)。InvokeRequired检查对象是否属于当前线程,基本上意味着this.textBox7.Text = text;永远不会在除textBox7所属的线程之外的任何线程上运行。 - Nolonar
4个回答

4
  • 另一个线程调用了SetText
  • 因为它不是创建Form的线程,所以需要使用Invoke
  • this.Invoke再次调用带有指定参数的SetText。还可以查看这里
  • 现在,SetText从UI线程调用,无需Invoke
  • else块中,我们确信文本已经安全地设置为线程安全

2

InvokeRequired 用于检查语句是否在主 UI 线程中执行或在其他线程中执行。

如果语句正在其他线程中执行而不是在 UI 线程中执行,则使用 Invoke 来避免引发任何 CrossThread 异常。


2
else绝对是必需的。
这段代码的作用是允许您从任何线程安全地调用SetText。如果您从UI线程之外的线程调用它(if块),它会透明地将调用转发到UI线程(else块),这是唯一能够访问控件以读取或设置其文本的线程。
盲目地使用this.textBox7.Text将在非UI线程上引发异常。

1

除了其他答案之外,这是一种常见的模式(特别是在被调用方法包含大量逻辑的情况下) - 如果InvokeRequired返回true,则从UI线程回调到同一方法:

private void SetText(string text)
{
    if (InvokeRequired)
        BeginInvoke(new Action<string>((t) => SetText(text)));
    else
        textBox7.Text = text;
}

那样你就不必在ifelse中重复逻辑了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接