Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Threading Method Question

Tags:

c#

lambda

I'm using the following method to show a modeless Message Box.

public void ShowMessageBox(string Message)
{
  var thread = new Thread(
    () =>
    {
      MessageBox.Show(Message);
    });
  thread.Start();
}

The "() => {...}" is something I've never seen before. What is the name for this code pattern?

Also, thread.Start starts the thread, and it automatically closes once the "()=>{...}" method completes (when the Message Box is OK'ed), right? If so, can you please point me to some official documentation saying that the thread closes automatically?

Thanks!

like image 829
sooprise Avatar asked Dec 07 '22 02:12

sooprise


2 Answers

It's the lambda operator, and read as "goes to". MSDN has a good intro: Lambda Expressions (C# Programming Guide)

One concern with your example is that you're spinning up a new thread to update the UI, the UI is intrinsically single-threaded, so background updates are generally the wrong thing to do (unless you're manually/explicitly checking InvokeRequired and calling Invoke() as needed.


Regarding the UI threading...

In WinForms every Form or Control is created on a particular thread (the "UI Thread"), and you can think of that thread as owning that control (not exactly correct, but a good way to conceptualize it). Updating the UI from that thread is safe, updating the UI from another thread runs the risk of collisions and corruption and all the usual risks of parallel/async programming.

...So... how do you safely update the UI from a background thread without blocking the UI? In short--you can't--the best you can do is block it for the bare minimum required to update the UI. This is where InvokeRequired and Invoke() come in...

Here's a sample: you should be able to drop this into the code-behind of a new form with a button and textbox.

To use:

  • Try commenting out either the call to SetTextAsyncSafe() or SetTextAsyncSafe() -- running both could confuse you since they won't necessarily execute in the order they're called (they're running async, remember?).

  • Then set a breakpoint on SetText(). You should see the "safe" call will actually call the method twice--the first call will detect InvokeRequired and will call the method a 2nd time for the correct thread by Invoke()'ing to it.

  • You should see an Exception thrown when SetTextAsyncUnsafe() actually gets to the textBox1.Text = value; statements. The exception will be an InvalidOperationException with a message stating "Cross-thread operation not valid" -- you can google this term for more details.

The code:

private void button1_Click(object sender, EventArgs e)
{
  SetTextAsyncSafe("This update was made from the UI Thread by using Invoke()");
  SetTextAsyncUnsafe("This update was made directly from the background thread and can cause problems");
}

private void SetTextAsyncUnsafe(string value)
{
  new Thread(() => SetText(value, false)).Start();
}

private void SetTextAsyncSafe(string value)
{
  new Thread(() => SetText(value, true)).Start();
}

private void SetText(string value, bool checkInvokeRequired)
{
  if (checkInvokeRequired) 
  {
    if (InvokeRequired) 
    {
      Invoke(new Action(() => SetText(value, checkInvokeRequired)));
      return; // early exit
    }
  }

  textBox1.Text = value;
}
like image 65
STW Avatar answered Dec 28 '22 03:12

STW


That is a Lambda. In this case, you're using it to create a new anonymous method that will be run when the new Thread is started.

It's the (near) equivalent of:

public void ShowMessageBox(string Message)
{
    var thread = new Thread(ShowBox);
    thread.Start(Message);
}

public void ShowBox(object message)
{
    MessageBox.Show(message.ToString());
}
like image 29
Justin Niessner Avatar answered Dec 28 '22 03:12

Justin Niessner