5

Everybody knows, that updating UI from background thread is not allowed (or not?)

I did a little experiment. Here is a piece of code:

var thread = new Thread(() => progressBar1.Increment(50));
            thread.IsBackground = true;
            thread.Start();
            thread.Join();

I put this code in some button click handler. And know what? My progressbar is incrementing...From background thread. And now I am confused. I don't understand how it is possible and what am I doing wrong

Toddams
  • 1,489
  • 15
  • 23
  • 3
    You misunderstood the idea. Nothing to do with UI element, but with what is created in the UI thread. For example. If you put `progressBar1` in your main form via design view, this code would trigger an error. – varocarbas Dec 19 '15 at 18:37
  • 1
    But according to this link - https://msdn.microsoft.com/en-us/library/ms171728%28v=vs.110%29.aspx any access to the control element from the thread other than the one that created the control is not allowed – Toddams Dec 19 '15 at 18:43

3 Answers3

7

I can update UI from background thread, why?

Most probably you can do that when running outside the debugger. This is because that protection is controlled by the Control.CheckForIllegalCrossThreadCalls Property. Let take a look at reference source

private static bool checkForIllegalCrossThreadCalls = Debugger.IsAttached;
public static bool CheckForIllegalCrossThreadCalls {
    get { return checkForIllegalCrossThreadCalls; }
    set { checkForIllegalCrossThreadCalls = value; }
}

As you may see, this protection is enabled by default only when you are debugging.

If you add the following line in your Main method (before Application.Run)

Control.CheckForIllegalCrossThreadCalls = true;

your code will not work anymore.

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • 1
    Note that such calls are still wrong/buggy even when `CheckForIllegalCrossThreadCalls ` is set to false. This setting causes such bugs to be easier to discover and fix. – Brian Dec 21 '15 at 15:44
5

Everybody knows, that updating UI from background thread is not allowed

Not everyone knows that. But it is true. Updating most UI elements from threads other than the UI thread is wrong.

I don't understand how it is possible

You pour a bunch of sand into your car's oil sump. You're not supposed to do that. So how is it possible that you just did so? Seems like a strange question to ask, doesn't it?

Is the car required to stop you from doing so? No. Is it required that the engine stops running when you do so? No. Will the engine break eventually? Probably. But not necessarily.

The engineers who designed your car assumed that you would not do something so wrong, so they did not build in any safety systems to prevent or detect this problem.

what am I doing wrong?

You're updating the UI from a background thread. Don't do that. But the runtime is not required to provide a safety system that prevents or detects your error. It is not required to produce an error when you do something that you shouldn't be doing in the first place. It can do so if it wants, or not, at its discretion.

Or, think about it this way. Suppose you were implementing the runtime so that it had the property you thought it had: that the runtime will always detect bad cross-thread calls and produce an error when they happen. That's a feature. Someone has to design, write, test, and maintain that code. What does the code look like, and what are all the costs associated with it?

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Nice explanation. I thought changes just would not take effect from background thread, now everything became clear, thank you – Toddams Dec 19 '15 at 22:00
  • "Updating most UI elements from threads other than the UI thread is wrong." Just out of curiosity, are there any UI elements that can be updated from Non-UI threads? – Luca Cremonesi Dec 21 '15 at 22:12
  • 2
    @LucaCremonesi: The weasel-word "most" is used there to forestall the possibility of pedantic SO users from commenting "no, the FrobButton widget made by Frobozz Corporation in their Fribble Controls 2.5.6 is safe to call from any thread". A universal statement only needs one counterexample to be contradicted; "most" needs 50% of cases to be counterexamples to be contradicted. – Eric Lippert Dec 21 '15 at 22:37
-1

Like varocarbas says any component you put into your designer will throw Cross thread exception.

to access between thread you need to use invke, beginInvoke.

try to run

BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (s1,e1) => 
{
    textBoxt1.Text = "foo";  // Exception here
} 
bw.RunWorkerCompleted += (1s, e1) =>
{
    textBoxt1.Text = "foo";  // No exception here off UI thread
}
bw.RunWorkerAsync();

instead replace

bw.DoWork += (s1,e1) => 
{
    this.Invoke((MethodInvoker) delegate 
   {
        textBoxt1.Text = message;
   });  // No Exception now
} 
Marco Luongo
  • 397
  • 4
  • 13