ThreadPool如何直接访问另一个线程的控件?

本文关键字:控件 线程 另一个 何直接 访问 ThreadPool | 更新日期: 2023-09-27 18:03:34

我听说线程不能直接访问其他线程的控制。

教授给了我们一个片段

private void UpdateUI()
{
    if(this.InvokeRequired)
        this.Invoke(new MethodInvoker(UpdateUI));
    else
        this.Refresh();
}

,并说InvokeRequired属性返回false,如果线程不是控件的所有者,那么我们应该调用Invoke()方法来告诉所有者线程执行UpdateUI()方法。然后更新UI。

但最近,只是出于好奇,我评论了InvokeRequiredInvoke()

private void UpdateUI()
{
    //if(this.InvokeRequired)
        //this.Invoke(new MethodInvoker(UpdateUI));
    //else
        this.Refresh();
}

并且很惊讶地看到ThreadPool可以访问另一个线程的控制,现在我觉得我还没有完全理解ThreadPool的概念。

这是完整的代码。

using System;
using System.Threading;
using System.Drawing;
using System.Windows.Forms;
class MainForm : Form
{
    public MainForm()
    {
        this.Text = "Hello WinForms";
        ThreadPool.QueueUserWorkItem(Clock);
    }
    private void Clock(object state)
    {
        for(;;)
        {
            Thread.Sleep(1000);
            UpdateUI();
        }
    }
    private void UpdateUI()
    {
        //if(this.InvokeRequired)
        //    this.Invoke(new MethodInvoker(UpdateUI));
        //else
            this.Refresh();
    }
    protected override void OnPaint(PaintEventArgs pe)
    {
        using(Pen pen = new Pen(Color.Red, 2))
            pe.Graphics.DrawRectangle(pen, 20, 20, 125, 30);
        pe.Graphics.DrawString(DateTime.Now.ToString(), this.Font, Brushes.Blue, 25, 30);
    }
    [STAThread]
    public static void Main()
    {
        Application.Run(new MainForm());
    }
}
谁能告诉我这是怎么发生的?

谢谢。

ThreadPool如何直接访问另一个线程的控件?

在你发布的应用程序中,你没有从ThreadPool访问任何控件,你只是在窗体上调用Refresh。这实际上是向窗体发送一个消息,告诉窗体自己重新绘制自己,但是该消息是在主GUI线程上接收的,而不是从ThreadPool线程接收的。

因此,您不需要调用在您的情况下,因为您不做任何跨线程活动。OnPaint方法通过windows消息泵间接调用,而不是直接从Refresh方法调用。

如果你要尝试,例如,从后台线程设置文本框的文本…它将抛出一个异常,并且您将需要使用Invoke模式使其工作。

ThreadPool是一个可重用的线程池,您可以使用它来执行代码。ThreadPool线程运行在一个独立于UI线程的线程上。

你关心UI线程。任何线程都可以访问UI线程,但是,它不是线程安全的。这是这里的关键词。它可能起作用,也可能不起作用。如果是,那么,你很幸运。

不线程安全仅仅意味着你不能保证一个一致的和预期的行为。现在设置一些东西可能会工作,但一毫秒后,它可能会无缘无故地随机失败。

对于WinForms, . net默认检查跨线程调用,但我们可以通过将System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls设置为false来禁用此功能并在非线程安全的上下文中访问UI。然而,禁用这意味着我们需要预期并迎合随机行为。

你可以从其他线程访问元素,但这是不安全的。

如果多个线程试图同时访问您的控件,它将抛出异常。因为WF控件不是线程安全的