Searock
Searock

Reputation: 6498

How can ThreadPool directly access the controls of another thread?

I have heard that thread cannot access controls of other threads directly.

So our professor gave us a snippet

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

and said that InvokeRequired property returns false it the thread is not the owner of the control and then we should call Invoke() method to tell the owner thread to execute UpdateUI() method. Which then updates the UI.

But recently, just out of curiosity I commented InvokeRequired and Invoke()

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

and was surprised to see that ThreadPool could access controls of another thread and now I feel that I haven't completely understood the concept of ThreadPool.

Here's is the complete code.

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

Could someone please explain me how does this happen?

Thanks.

Upvotes: 3

Views: 2206

Answers (3)

Alexander Molodih
Alexander Molodih

Reputation: 1936

You can access from other thread to elements, but it's not safe.

If several thread try to access you control concurrently it throws an exception. Because WF controls not thread safe.

Upvotes: 1

Erik Funkenbusch
Erik Funkenbusch

Reputation: 93464

In the application you posted, you are not accessing any controls from the ThreadPool, you are only calling Refresh on the form. This actually sends a message to the form to tell itself to redraw itself, but that message is received on the main GUI thread rather than from the ThreadPool thread.

Therefore, you need not Invoke in your case because you do not do any cross thread activity. The OnPaint method gets called indirectly via the windows message pump rather than directly from the Refresh method.

If you were to try and, for example, set the text of a textbox from a background thread... it would throw an exception, and you would be required to use the Invoke pattern to make it work.

Upvotes: 3

foxy
foxy

Reputation: 7672

The ThreadPool is a pool of reusable threads that you can use to execute code. The ThreadPool threads run on a separate thread to the UI thread.

You're concerned with the UI thread. Any thread can access the UI thread, however, it is not thread safe. That's the key word here. It might work, it might not. If it does, well, you had good fortune.

Not thread safe simply means that you are not guaranteed a consistent and expected behaviour. Setting something now might work, but a millisecond later, it might fail randomly without reason.

With WinForms, .NET by default checks for cross-thread calls, but we can disable this and access the UI in a non-thread safe context by setting System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls to false. However, disabling this means that we need to expect and cater for random behaviour.

Upvotes: 3

Related Questions