Tuesday, February 27, 2007

Avoid Invoke(), prefer BeginInvoke()

This is another post in a series that deals with asynchronous behaviour (see also here and here).

The difference between Control.Invoke() and Control.BeginInvoke() is:

  • BeginInvoke() will schedule the asynchronous action on the GUI thread. When the asynchronous action is scheduled, your code continues. Some time later (you don't know exactly when) your asynchronous action will be executed.
  • Invoke() will execute your asynchronous action (on the GUI thread) and wait until your action has completed.

A logical conclusion is that a delegate you pass to Invoke() can have out-parameters or a return-value, while a delegate you pass to BeginInvoke cannot (you have to use EndInvoke to retrieve the results).

My advice is: always use BeginInvoke() if you can. Reasons:

  • Because Invoke() causes one thread to wait for another thread, it is likely to cause deadlocks. Imagine that your application has a dedicated worker thread that uses Invoke() to execute some work on the GUI thread. Now image that during this work, your GUI code needs to execute something on the worker-thread. It will be blocked forever because your worker-thread is already busy waiting for your GUI-thread.
    In this simple example it might be easy to spot the problem. In a big application developed by many people it will not always be this easy. Therefore it is better to find a pattern that avoids blocking altogether.

    Note that in this example you might think that a threadpool solves your problem, because then you have multiple workerthreads. However the problem will still occur under high load, this is called threadpool starvation and it is a very complex problem. Because it only occurs under high load, it is a very dangerous thing that is very difficult to debug.
  • Invoke() will cause forced threadswitches that will decrease the scalability of your application.

    First consider BeginInvoke: when it is called, a delegate is scheduled to be executed on the other thread. However your current thread will continue until the operating system decides that it's done enough work. Only then will the other thread (GUI thread) be executed, and your delegate will be run. If other delegates were also scheduled using BeginInvoke(), they will be executed as well.

    Now consider Invoke: when you call it, the OS immedeately has to stop your current thread and schedule the other thread.
    When more than one Invoke()-statement is done, a threadswitch will be needed every single time (whereas multiple BeginInvoke-requests can be bundled in one threadswitch).
    Excessive threadswitches will seriously hurt performance when your application is under a high load.

Conclusion: avoid using Invoke().

Thursday, February 15, 2007

Don't confuse Control.BeginInvoke() with Delegate.BeginInvoke()

In my last article I used the BeginInvoke() method to execute a delegate on the GUI thread.

Here is the definition of the delegate (this is just an example):

delegate void Invoker(string parameter);

And here you see where the delegate is used:

// Execute on the GUI thread this.BeginInvoke(new Invoker(SetTitleSafe), title);

Some people may confuse this with the BeginInvoke-method on a delegate, like this:

Invoker i = new Invoker(SetTitleSafe); // Execute on a threadpool thread i.BeginInvoke();

Note however that these are two completely different concepts!

Control.BeginInvoke is used to execute code on the GUI thread, while Delegate.BeginInvoke is used to execute code on a threadpool thread. For more information, click here.

One important difference is that when you invoked Control.BeginInvoke you are not obliged to call Control.EndInvoke. However, when you call Delegate.BeginInvoke you should also call Delegate.EndInvoke, otherwise you will have a memory leak!

This obligation to call EndInvoke may likely complicate your code. Mike Woodring has written a nice helper-class that will help you with this. Or you can also use Threadpool.QueueUserWorkItem (this is also used in the back by Delegate.BeginInvoke).

Tuesday, February 13, 2007

Simple pattern to invoke GUI from another thread

If you are making a GUI application and you are using multiple threads, there is one very important rule: GUI controls can only be accessed from the GUI thread. This is inherent to Windows development and is not a limitation of .NET.

Let me first say that although this seems to be an annoyance for the developer, this is actually a great thing! It means that while you are developing a GUI application you generally don't have to worry about threading issues (locks, deadlocks) because you know that all GUI-access is done from a single thread.

But of course there are situations where you want to start background processing on a seperate thread and access the GUI from this thread. Take for instance this simple example:

public void SetTitleUnsafe(string title) { // When invoked from another thread, this next statement is illegal: this.Text = title; }

If you call this method from a thread that is not a GUI thread, everything may seem to go well at first sight. But because we violated the very important rule, the behaviour of our application is now undefined. Things may (and will) start to go wrong very unpredictably, sometimes much later when there is no obvious relationship with the violation that was made. This makes this problem very hard to find. Among the things that could happen is GUI-events to become 'lost' and the GUI to become unresponsive.

Luckily, form Visual Studio 2005 onward you get a nice error-message when you violate this rule while the debugger is attached:

So now you at least get an immedeate notification that you made a mistake. This one of the reasons why I advise to run your code from Visual Studio (using F5) while you are developing.

To get around our threading-violation, Winforms provides these helper-methods: BeginInvoke, EndInvoke, Invoke, InvokeRequired. But even with these methods available it may not be obvious how to use them in a correct and simple way.

That's why I present this pattern:

delegate void Invoker(string parameter); public void SetTitleSafe(string title) { if (this.InvokeRequired) { // Execute the same method, but this time on the GUI thread this.BeginInvoke(new Invoker(SetTitleSafe), title); // we return immedeately return; } // From here on it is safe to access methods and properties on the GUI // For example: this.Text = title; }

As you can see, you will need to define a delegate that matches your method (or use an existing delegate that is defined elsewhere, such as the System.Windows.Forms.MethodInvoker). This is how the pattern works:

  • When the method is called from a thread that is not the GUI thread, InvokeRequired will be true. The method will be wrapped in a delegate and passed to the BeginInvoke method (together with the parameters). We return immedeately. BeginInvoke guarantees that some time later our method will be called on the GUI thread.
  • When the method is called on the GUI thread, InvokeRequired returns false so we just go forward and access the GUI in any way we like.

This is in my opinion the simplest and shortest pattern that is always correct.

From .NET 2.0 onwards the same pattern can be written using an anonymous method but that is less readable in my opinion, so I prefer to keep this pattern.

Also in .NET 2.0 you can use the BackgroundWorker class that handles all the details behind your back. But the same principle still applies: never access GUI from another thread!

Friday, February 02, 2007

Rethrow an exception using throw;

It is not uncommon that you want to rethrow an exception in a catch-block. This happens if you need to cleanup some state in the catch-handler, but you still want to inform the application that something has gone wrong.

You often see this implemented as such:

static void SomeMethod()
{
    try
    {
        MethodThatCanThrowAnException();
    }
    catch (Exception ex)
    {
        // Do stuff (cleanup)
        throw ex; // WRONG - DO NOT USE THIS!
    }
}

There is a subtle problem with this: rethrowing the existing exception-object will reset its stacktrace. Whoever catches this exception and examines the stacktrace will think that it was caused by your code.

It is better to do this:

static void SomeMethod()
{
    try
    {
        MethodThatCanThrowAnException();
    }
    catch (Exception ex)
    {
        // Do stuff (cleanup)
        throw; // does not reset the stacktrace
    }
}

Now whoever catches this exception will see the complete stacktrace and can see the originator who caused the exception. This might save a lot of time for whoever has to debug the problem.

 

Another valid possibility is to throw a new exception, but set its InnerException propery to the original exception like this:

catch (NullReferenceException ex)
{
    // Do stuff (cleanup)
    throw new ObjectNotInitializedException(ex);
}
Whoever catches this exception can view a separate stacktrace for your exception and the InnerException. I would use this second pattern if the new exception that you throw contains more information about the cause of the problem than the inner-exception. For instance if the inner-exception is a NullReferenceException, your exception can give more context (e.g. the object is not yet initialized).

Kristof

Public fields and properties are not compatible

If your class wants to expose some data, you have two possibilities:

  1. Use a public field
    public class Person { public string Name; }
  2. Use a public property that is backed by a private field
    public class Person { private string name; public string Name { get { return name; } set { name = value; } } }

The general advise is that you should not have any public fields, thus you should always use properties. However some people suggest that you can start out with a public field and that you can easily change it into a property when the need arises.

But this is not true for two reasons:

  1. A public field and a property are binary incompatible. When you change your public field into a property you will have to recompile all the clients of your class.
  2. A public field and a propery are also incompatible at source-code level. A public field can be passed as a ref- or out-parameter while a property cannot. So when you change your public field into a property, you may have to actually change the client code which may not be a trivial task.

So my advise: unless you have *very* strict performance considerations always use properties.

Regarding performance, keep in mind that a simple propery that is not marked as virtual (or that is part of a sealed class) will likely be inlined by the compiler so there shouldn't be any performance impact at all (in release-builds).

Kristof.