【问题标题】:Why can't I access properties of an UI control from another thread?为什么我不能从另一个线程访问 UI 控件的属性?
【发布时间】:2014-11-11 12:58:42
【问题描述】:

我读到无法从另一个线程(不仅是 GUI,而且所有 2 个不同的线程)访问 UI 元素,并看到了如何解决它的代码,但没有找到解释为什么我不能这样做?

【问题讨论】:

    标签: c# multithreading user-interface


    【解决方案1】:

    MSDN 不允许这样做的原因:

    对 Windows 窗体控件的访问本质上不是线程安全的。如果您有两个或更多线程操作控件的状态,可能会强制控件进入不一致的状态。其他与线程相关的错误也是可能的,包括竞争条件和死锁。确保以线程安全的方式访问您的控件非常重要。

    所以从技术上讲,我是可能的(也许他们在设计上忽略了它),但问题是微软的底层代码不是线程安全的。这可能与 Windows 的内部工作原理有关,并且在其 Win32 UI 模型中缺乏线程安全性。

    【讨论】:

    • 或者。这是一个设计决策,因为编写线程安全的 UI 控件是微不足道的 - 如果控件微不足道 - 或者如果不是,则可能是一个噩梦。在许多情况下,当一个人强制子系统进入单线程行为时,它是有道理的 - 即很多事情更容易。这就是 MS 在这里所做的。
    • @TomTom:好点。没想到这一点,但这在性能方面也很有意义。
    • 它使调试更容易。 Java 没有使用它(几年前我做 Java 时),他们花了数年时间才发现一个罕见的竞争条件挂起他们的 UI 库。我在交易中使用了类似的方法——策略是单线程的。使编写它们变得更容易并且它们不会变慢。实际上更快,因为您不需要到处传播锁定代码。
    • 几乎每个 GUI 框架都做出了相同的决定——拥有线程安全的 GUI 代码/事件循环/等等。很难,工作量很大,并且会影响性​​能。相反,大多数 GUI 框架提供了一种将消息或代码从另一个线程注入 GUI 线程的方法。
    • 是和否 - 正如 nos 所说,这是一个标准模式。折衷通常是最小的,并且易于编程的收益简直令人惊讶;)
    【解决方案2】:

    您不能从除 GUI 线程(主线程)之外的任何其他线程对 GUI 进行更改。话虽如此,如果您想从另一个线程更改控件,则可以毫无问题地从任何线程读取控件(文本框等)的数据,您需要使用类似这样的东西:

    textBox1.Invoke((MethodInvoker)(() =>
    {
        textBox1.Text = "text changed from another thread";
    }));
    

    这样做的缺点是,现在您从中调用它的线程被阻塞,直到对文本框的更改完成。如果您不经常从线程更新控件,这不是问题,但如果您想经常这样做,则需要创建第三个线程来根据工作线程正在做什么来处理更新。像这样的

    List<string> list = new List<string>();
    Thread workThread = new Thread(dowork =>
    {
        //random work
        for(int a = 0; a< 1000000;a++)
        {
            list.Add(a+" iteration");
            Thread.Sleep(10);
        }
    });
    workThread .Start();
    bool updateThreadWorking = true;
    Thread updateThread = new Thread(dowork =>
    {
        while(updateThreadWorking)
        {
            while(list.Count > 0)
            {
                listBox.Invoke((MethodInvoker)(() =>
                    listBox.Items.Add(list[0]);
                }));
                list.RemoveAt(0);
            }
            Thread.Sleep(200);
        }
    });
    updateThread .Start();
    

    现在工作线程正在全速工作而不会被 UI 阻塞,并且 UI 仍在更新当前状态

    【讨论】:

    • 您阅读了吗?喜欢这个问题?他问为什么,而不是什么。你基本上提供了零信息——你用一个很好的例子重复了这个问题,但没有解释任何事情。
    猜你喜欢
    • 2013-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 2021-07-30
    • 1970-01-01
    相关资源
    最近更新 更多