Home > Uncategorized > Invoke: Is that like… magic?

Invoke: Is that like… magic?

First there were threads and then there were invokes. Then came along developers and well the rest is history.

Understanding threads and solving timing issues related to threads is an art. In fact, finding the exact origin a threading related issue is a talent in itself. The kind that comes with experience and solid understanding of the framework and CLR. Of course, it wouldn’t hurt to read my articles once in a while.

Some people complained that my last article as a tad too long. So I’ll try to keep this one as short as possible. [Alex 1:33 AM: I tried but I couldn't] For those of you who are starting off on threading in C# will benefit from reading my previous article here.

Except for the most simplest of applications, most windows forms apps will end up using multiple threads to speed up application execution. Let us say you have a database and you want to perform a database write of 10,000 records which is expected to take a significant amount of time to complete. If you were to execute this operation on the main thread, the UI would appear to be hung till the execution of the operation completes. By todays standards, this is totally unacceptable.

Let me give you a little more background on why this happens. Every Windows forms application (even a console app) starts off with one thread. This is known as the application’s main thread or in case of Windows forms application, the UI thread. Unless otherwise created, this will be the one and only thread available to the application till it terminates. If you add a button to your form, that button is created by the main thread on the main thread, and the main thread owns it. Remember this. Its important.

Windows communicates user events such as mouse clicks to your application through messages. Your application handles these messages through a mechanism called as the message pump. So where is the message pump in your application? Well, have a look inside your main method and you will see this line:

Application.Run(new MyForm());

Application.Run creates an instance of your form and displays it. It also maintains the message pump for your application. So when you click on a button in your form, windows notifies your application regarding the mouse click by sending a message. Your message pump intercepts the message and makes it available in your application in the form of events. You, as a developer, wire up the event to an event handler and viola… Hello World.

What you should also know is this: the message pump also executes inside, drum roll please, the UI thread! So when your application is performing that database operation, it is doing so inside the main thread. What this means is that no one is running the message pump anymore as the only available thread is busy. During this time if you try to interact with your application, it appears to be hung because no one is processing the messages that are being sent to your application.

Now that we fully understand the problem, the solution seems to be simple: launch the lengthy operation in a separate thread. This leaves the UI thread free to pump away.

Now lets say while you are doing this lengthy operation (in a different thread), you want to inform the user of the progress of the operation. For this you have a progress bar in your main form and as you progress through your lengthy operation, you update the progress bar. Sounds simple doesn’t it? How would you do it?

Listing 1:
DoDatabaseUpdate()
{
for (;;) //Some loop
{
//Code for the lengthy operation


progressBar.PerformStep(); //Update the progress bar
}
}

If you thought the above listing was the right then you really, really need to read the rest of this article. Twice.

In the beginning of this article I had asked you to keep in mind something that I said was important, which in all probability, you would have forgotten by now. Here it is again: The thread that creates the control owns the control. What this means in short is that your application window, the buttons, text boxes and all other controls that you dragged and dropped into your form are owned by your UI thread.

Engrave the next statement in your brain: You should only manipulate a control on the thread on which it was created.

If you use listing 1 to update your progress bar you will get an error similar to the one below:

General Exception: System.InvalidOperationException: Cross-thread operation not valid: Control ‘progressBar’ accessed from a thread other than the thread it was created on.

A very important note:
In .net 1.1 the code in listing 1 will compile and run without any exception. But from .net 2.0 onwards this will cause a runtime exception as shown above.

There is a way to ignore this check in 2.0 though. Just set the control’s CheckForIllegalCrossThreadCalls property to false

Control.CheckForIllegalCrossThreadCalls = false;

PS: This property does not exist in .net 1.1

In .net 2.0 if you set the above property for a control and make an illegal cross thread call such as the one in listing 1, no runtime exception will be thrown. In .net 3.0 and above, setting this property will make the debugger to stop notifying you when such an exception occurs, but it will still cause a runtime exception in your release build.

All said and done, I highly recommend that you DO NOT set this property to false if you are using .net 2.0. The framework is giving you a chance of uncovering such issues as and when they happen. Take the hint and fix the problem. Setting this property is like ignoring a time bomb. Its just a matter of time.

Before the question comes up, let me answer it myself. If .net 1.1 doesn’t give an error does it mean that this operation is legal? Thats like stealing and not getting caught. Just because you can do it doesn’t make it right. Its a matter of timing and a bit of luck. If you are using .net 1.1 and you find that your application suddenly crashes or completely disappears from the screen for no particular reason, check your code for cross thread calls. And I highly recommend that you move your code to 2.0 as soon as possible. Microsoft has fixed a lot of performance and functional issues in 2.0. Do it now. You can thank me later.

Now lets see how we can solve our little problem. For situations like this, .net provides a special method: Invoke. Invoke executes delegate on the thread that owns the control’s underlying window handle.

Invoke is an overloaded method.

Control.Invoke(delegate)
Control.Invoke(delegate, object[])

Lets understand them by solving our problem shown in listing 1.

Listing 2:
//Declare a delegate (class member)
private delegate void UpdateProgressBar();

//Create an instance of the delegate for us to use (class member)
private UpdateProgressBar updateProgressDelegate;

void StepProgressBar()
{
progressBar.PerformStep();
}

//Method executed on a different thread
DoDatabaseUpdate()
{

//Associate a method to our delegate (defined above)
updateProgressDelegate = new UpdateProgressBar(StepProgressBar);
for (;;) //Some loop
{
//Code for the lengthy operation


this.Invoke(updateProgressDelegate );//Update the progress bar by calling the delegate
}
}

There you have it, the new an improved thread safe version of our little program. Lets analyze each step. Since Invoke takes a delegate as a parameter, we have to create a delegate first. A delegate is like a function pointer in C++. A delegate encapsulates a method inside it. Think of it as an indirect way of calling the method. A delegate can only encapsulate methods that matches the delegate’s signature. For example, our delegate UpdateProgressBar can encapsulate any method that returns void and takes zero parameters. If we wanted the delegate to to encapsulate a method that returns an int and accepts one integer parameter the delegate would look like this:
private delegate int UpdateProgressBar(int step);

The next step is to create an instance of the delegate. This is done in the next line:
private UpdateProgressBar updateProgressDelegate;

Then encapsulate the method by doing
updateProgressDelegate = new UpdateProgressBar(StepProgressBar);
and inside the StepProgressBar method we call the ProgressBar’s PerformStep method.

This delegate object is then passed to the Invoke method.

Ok, now comes the interesting part. Note that we are calling Invoke on this. This means that you are calling Invoke on your form. You could also have called invoke on the progressbar control. It really doesn’t make a difference since both the form and the progressbar are created on the same thread. Invoke requires a windows handle to execute the delegate. If for some reason the control’s handle has not been created yet, invoke will search up the controls parent chain till it finds a control with a handle and executes the delegate on the thread that owns the handle. Whew!

Here is some information you wont find in most articles. Many people think that Invoke is an asynchronous operation. It is not. When you call invoke, your application switches to the thread that owns the control, executes the method and returns. Also if you try to call invoke on a control and invoke cannot find a handle anywhere in the chain, it will throw a runtime exception Understanding this little bit of information can go a long way in detecting deadlocks in multithreaded applications.

Lets quickly go through the overloaded version of Invoke:
Control.Invoke(delegate, object[])

The first parameter is again a delegate and the second parameter is a list of arguments that you can pass to the delegate. Lets rewrite the program so that StepProgressBar now takes an int parameter.

Listing 3:

//Declare a delegate (class member)
private delegate void UpdateProgressBar(int step);

//Create an instance of the delegate for us to use (class member)
private UpdateProgressBar updateProgressDelegate;

void StepProgressBar(int step)
{
progressBar.Value += step; //Update the progress bar with the value that is passed
}

DoDatabaseUpdate()
{

//Associate a method to our delegate (defined above)
updateProgressDelegate = new UpdateProgressBar(StepProgressBar);
for (i=0;i<10;>
{
//Code for the lengthy operation


this.Invoke(updateProgressDelegate, new object[]{i} );//Update the progress bar by calling the delegate
}
}

The above program is pretty self explanatory. I’ll leave it to you to figure out.

One more thing before we wrap up. What if DoDatabaseUpdate was executed on the main thread instead of a worker thread? In this case we really don’t need to do an Invoke. In fact we shouldn’t. Invoke carries a small performance hit which we can avoid if the method was being executed on the main thread. So in cases where we have methods that may be executed on the main thread and/or on a worker thread depending on the program logic, .net provides a property by which we can figure out whether Invoke is really required or not. This property is called (no points for guessing) InvokeRequired.

Lets rewrite listing 2 using InvokeRequired.

Listing 4:

DoDatabaseUpdate()
{

//Associate a method to our delegate (defined above)
updateProgressDelegate = new UpdateProgressBar(StepProgressBar);
for (;;) //Some loop
{
//Code for the lengthy operation


if (InvokeRequired)
this.Invoke(updateProgressDelegate );//Update the progress bar by calling the delegate
else
progressBar.PerformStep();
}
}

There, now our program is complete. If DoDatabaseUpdate is called from the main thread, it will access the control directly (and avoid the invoke overhead) and if its being called from a different thread, an invoke is performed.

Note:
For a control .net guarantees one property and three methods to be thread safe: InvokeRequired, Invoke, BeginInvoke and CreateGraphics.

I know that I promised to describe a deadlock scenario when we use Invokes and locks, in the last edition. But its already 1:30 AM where I live and my eyes are slowly giving up on me. So that will have to wait till next time. Stay tuned.

Author’s Note [Added 19-02-2008] :
Please do keep in mind that invoke is required only for controls (such as forms, buttons, treeviews etc). You don’t have to use invoke if you are modifying, say, an integer variable or an array list from another thread. They can be directly accessed from other threads. You will, of course, need to provide some synchronization mechanism if multiple threads will be accessing them simultaneously.

Code safely.
Alex

Categories: Uncategorized Tags: , , ,
  1. Anonymous
    June 29th, 2008 at 00:06 | #1

    All this shit is present in MSDN documentation.

    AApara na maddalo code widgets.

  2. Bobby Alexander
    June 29th, 2008 at 05:44 | #2

    Most of the “shit” in most developer articles is present in some form or the other in MSDN.
    Lots of people have benefited from this article. As long as that is the case, the presence of this article is justified.
    Sorry you didn’t like it though. Maybe you can write something that doesn’t exist anywhere else on the internet and share the link so that the less enlightened ones like us can benefit?

    Cheers,
    Alex

  3. mafutrct
    February 26th, 2009 at 02:19 | #3

    Nice explanation, easy to follow and understand. Thanks!

  4. Vishal
    April 1st, 2009 at 00:08 | #4

    Alex dont worry about such IDIOTs, you did a good job cheers.

  5. Bobby Alexander
    April 1st, 2009 at 04:12 | #5

    Thanks Vishal. The encouragement helps. Keep visiting.

  6. Brij
    April 16th, 2009 at 10:30 | #6

    Dear Alex,

    Thanks for this article really it is very nice and easy understandble.

    You did a great job.

    Cheers,
    Brij

  7. Bobby Alexander
    April 16th, 2009 at 11:09 | #7

    Thanks Brij. I am glad it was of help. If you would like me to cover other aspects of .net, leave a comment or drop me a line. I’ll try my best to cover it.

    Cheers,
    Alex

  8. Anonymous
    May 28th, 2009 at 09:02 | #8

    DoDispose()
    {
    Anonymous.dispose;
    }

  9. Anonymous
    August 14th, 2009 at 09:47 | #9

    Thank you Alex,

    Really useful article.
    Wish you all the best, and new fine articles!
    Regards,
    Andy

  10. Bobby Alexander
    August 14th, 2009 at 10:35 | #10

    Thank you Andy.

  11. Elephant
    September 10th, 2009 at 05:24 | #11

    Thanks for the article.
    The only thing I would like to mention, if the worker thread is running, but the window was closed, you will get a runtime exception "Invoke or BeginInvoke cannot be called on a control until the window handle has been created". To avoid this, you need to write
    if( this.IsHandleCreated )
    this.Invoke(updateProgressDelegate);

    instead of
    this.Invoke(updateProgressDelegate )

    It solves the problem.

  12. Bobby Alexander
    September 11th, 2009 at 10:41 | #12

    Yup. That's right. Readers, do take note.

  13. Ranjit
    November 20th, 2009 at 05:06 | #13

    Thank a lot guys ….i was getting the same error["Invoke or BeginInvoke cannot be called on a control until the window handle has been created"]…..Elephant's comment helps to solve my problem……n Alex's post helps to understand the concepts clearly :)

  14. Jose
    February 26th, 2010 at 01:54 | #14

    My question then is:

    Does

    if( this.IsHandleCreated )
    this.Invoke(updateProgressDelegate);

    imply that IsHandleCreated is thread safe?

    Thanks for the article (and the good comments it generates!)

  15. March 19th, 2010 at 12:51 | #15

    @Jose As far as I can see, IsHandleCreated seems to be thread safe. Now, the Handle property is a different story. Trying to access it while the handle is not set will result in the handle being created, and if its done on a non UI thread, on the wrong thread!

    On a different note, along with IsHandleCreated it would be a good idea to check the IsDisposed property before updating the UI.

  16. Sanjay Sawant
    August 17th, 2011 at 15:19 | #16

    Thank you Alex for very good article.

    It’s gives nice & short explaination of Thread.

    Great work.

  1. No trackbacks yet.