Monday, February 06, 2006

Re: One Thread to rule them all

The generic question now. Have you guys come across any similar stuff in other languages? Java has had good support for threading since the early days and now in Java 5 this has been greatly enhanced. What about other languages? C++, C#. And anyone have info about dynamic languages like Lisp, Python etc?

I haven't seen the pattern (WorkerThread) that you wrote about... having one worker thread manage multiple tasks. I don't think this pattern is there in .NET. From what I understand, .NET has a different framework. There is probably a one to one similarity with the Threading package (atleast pre Java 5.0). However, .NET has an asynchronous framework built into all delegates. You can invoke delegates with myDelegate.BeginInvoke() and it will run asynchronously. That is, control will be immediately returned. I believe it picks a thread from a ThreadPool and executes it on that in the background. It's pretty nice in that all your own custom delegates get this feature for free.

When talking about UIs and threads there's another important aspect. Any updates to UI controls should only be made by the thread that created it. So if you have a background thread doing some work and you want to display a message in the UI when it's done, you can't simply access the control and update it directly. You need to marshal any updates through the 'owner' thread. Here's an example in C#...

// UI
public class ClientUI : System.Windows.Forms.Form
{
  private System.Windows.Forms.Label lblStatus;

...

  private void UpdateStatus()
  {
    if ( this.lblStatus.InvokeRequired )
    {
      this.lblStatus.Invoke( new MethodInvoker( this.UpdateStatus ) );
    }
    else
    {
      this.lblStatus.Text = "Done!";
    }
  }
}


All UpdateStatus() is doing is setting a property on a Label. UpdateStatus() would likely be registered as a callback. So when the background thread is done with its processing, it would raise an event and UpdateStatus() would get called. When it does, it can't just update the control since it is not the 'owner' thread. So it needs to marshal the call. This is done with this.lblStatus.Invoke(). MethodInvoker() is just a delegate which takes methods that don't have any arguments and returns nothing. Invoke() takes care of the marshalling.

What's the if/then statement for? InvokeRequired is a property on every UI control. It will tell you if the call was made from the thread that owns the control or not. If it does own it, it's just a direct update, if not, it needs to be marshalled.

All UI elements inherit from the Control class and all of them in turn have the InvokeRequired property and Invoke() method.

No comments: