Как ThreadPool может напрямую обращаться к элементам управления другого потока? - PullRequest
3 голосов
/ 24 июля 2011

Я слышал, что поток не может получить доступ к элементам управления других потоков напрямую.

Итак, наш профессор дал нам фрагмент

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

и сказал, что свойство InvokeRequired возвращает false в потокене является владельцем элемента управления, и тогда мы должны вызвать метод Invoke(), чтобы сообщить потоку владельца выполнить метод UpdateUI().Который затем обновляет пользовательский интерфейс.

Но недавно, просто из любопытства я прокомментировал InvokeRequired и Invoke()

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());
    }
}

Может кто-нибудь объяснить, как это происходит?

Спасибо.

Ответы [ 3 ]

3 голосов
/ 24 июля 2011

ThreadPool - это пул многократно используемых потоков, которые вы можете использовать для выполнения кода. Потоки ThreadPool работают в отдельном потоке в потоке пользовательского интерфейса.

Вы обеспокоены темой пользовательского интерфейса. Любой поток может получить доступ к потоку пользовательского интерфейса, однако это не потокобезопасный . Это ключевое слово здесь. Это может сработать, а может и нет. Если да, то тебе повезло.

Небезопасность потока просто означает, что вам не гарантируется согласованное и ожидаемое поведение. Установка чего-либо сейчас может сработать, но спустя миллисекунду это может произойти случайно без причины.

В WinForms .NET по умолчанию проверяет межпоточные вызовы, но мы можем отключить это и получить доступ к пользовательскому интерфейсу в не поточном контексте, установив для System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls значение false. Однако отключение этого означает, что мы должны ожидать и учитывать случайное поведение.

3 голосов
/ 24 июля 2011

В приложении, которое вы разместили, вы не получаете доступ к каким-либо элементам управления из ThreadPool, вы просто вызываете Обновить в форме.Это фактически отправляет сообщение в форму, чтобы сказать себе перерисовать себя, но это сообщение получено в основном потоке графического интерфейса, а не из потока ThreadPool.

Следовательно, вам не нужно вызывать Invoke, посколькуне занимайтесь кросс-нитьМетод OnPaint вызывается косвенно через насос сообщений Windows, а не напрямую из метода Refresh.

Если вы попытаетесь, например, задать текст текстового поля из фонового потока ...сгенерируйте исключение, и вам потребуется использовать шаблон Invoke, чтобы он работал.

1 голос
/ 24 июля 2011

Вы можете получить доступ из другого потока к элементам, но это небезопасно.

Если несколько потоков пытаются одновременно получить доступ к вашему элементу управления, он выдает исключение.Потому что WF контролирует не потокобезопасность.

...