views:

201

answers:

5

In a form, compare

BeginInvoke (new Action (() => {
    MessageBox.Show ());
}));

with

Invoke (new Action (() => {
    MessageBox.Show ());
}));

What is the difference, and when should I use one over the other? How is the behavior affected by the message pump of the MessageBox?

I did some testing and found that both methods block the UI.

The only difference is that Invoke is actually called instantly while BeginInvoke takes a (very short) time until the code is run. This is to be expected.

+3  A: 

BeginInvoke is asynchronous... this means that the calling thread won't wait for the called method to return.

So ok, dialog box always freezes the GUI. But the difference between begin invoke and invoke should be now clear:

Invoke waits for the called method to return BeginInvoke does not.

Simon
I don't agree. See edited question. --- Edit: Ah, yes, but aren't MessageBoxes always modal?
mafutrct
@mafutcrt: I think you confused two things. The MessageBox will still block the UI, but the actual act of call the lambda method is asynchronous when called via BeginInvoke. Just because that call is asynchronous does not mean the result of the call will be.
Jeff Yates
@Jeff: Yes, that's true. I suggest @Simon to include this explanation in his answer to make it more clear.
mafutrct
+1  A: 

For a MessageBox.Show, the question is mostly irrelevant.

The only difference is that with the BeginInvoke, the calling thread itself won't block, so it can continue doing things (cleanup, further processing, etc).

The UI thread will obviously block, because there's a modal window popped up waiting on user input to close it.

Adam Sills
+6  A: 

Simon is actually not wrong.

BeginInvoke is like sending a message to the UI thread and saying, "Do this as soon as you get a chance."

Invoke is like saying, "Do this right now. I'll wait."

Clarification: just because you tell the UI thread, "Do this right now," that doesn't mean you are God of the UI thread and can force it to drop everything it's doing. Basically, the key words in the above statement are "I'll wait."

The thing is, in your example code, the message you're sending to the UI thread is: call MessageBox.Show. Guess what? That's going to block the UI thread either way.

If you want to notice the asynchronous behavior of BeginInvoke, call it from a separate thread, put a breakpoint after the BeginInvoke call in your code, and notice that the breakpoint gets hit even while the message box is displayed (and the UI is blocked). If you call Invoke, the code won't continue until the user dismisses the message box.

Dan Tao
That's kinda the explanation I was looking for :)
mafutrct
Good explanation. Just wanted to note that both BeginInvoke and Invoke both say "Do this as soon as you get a chance.", but Invoke also adds "And I'll wait until you're done." Invoke isn't able to hurry things along, as you suggested ("Do this right now").
Allon Guralnek
@Allon: Yeah, I guess it's kind of subjective how you interpret those words. The thing is, in *real* life, you *also* can't **make** somebody do something **right now** -- but you can *tell* them to do it "right now" and stand there with your arms crossed, tapping your foot until they've actually done it. To me, this is the intent of `Invoke` -- you're right that it isn't like you can force it to abort whatever code it is currently executing; but you are effectively *saying*, at least, "Do this right now."
Dan Tao
"right now" implies timing on the doer's part, rather than on the asker's part which I think is misleading. The clarification you edited in only eliminates the possibility that there is no guarantee about timing, but still one might misconstrued that two simultaneous calls to `Invoke` and `BeginInvoke` might favor `Invoke` to run first, because it is more "urgent", and so might have a higher priority, which is not the case. "Do this, I've got work so call back when you're done" and "Do this, I'll wait right here till you're done" seem to me like more accurate personifications. +1 nevertheless.
Allon Guralnek
+9  A: 

BeginInvoke will invoke the delegate asynchronously, returning immediately having queued the delegate for execution independently of the current thread.

Invoke will invoke the delegate synchronously, blocking the calling thread until the delegate completes.

To see the difference, try the following code:

BeginInvoke(new Action(()=>Console.WriteLine("BeginInvoke")));
Console.WriteLine("AfterBeginInvokeCalled");

Invoke(new Action(()=>Console.WriteLine("Invoke")));
Console.WriteLine("AfterInvokeCalled");

You should see output similar to the following, where the "BeginInvoke" text is delayed due to its asynchronous execution:

AfterBeginInvokeCalled
Invoke
AfterInvokeCalled
BeginInvoke

Regarding the behaviour you observe, as it is only the act of calling the delegate that is synchronous or asynchronous; the content of the method may well cause the calling thread to stop or the UI to be blocked. In the case of showing a message box, regardless of whether the delegate is delayed using BeginInvoke or not, once the delegate is called, the UI will be blocked until the message box is dismissed.

Jeff Yates
A: 

While most of the answers are technically correct, they don't ask the obvious question.

Why do you want to wrap your MessageBox() calls in Invoke/BeginOnvoke in the first place?

There is simply no benefit in using BeginInvoke or Invoke in this situation, as Jeff explained.

It sounds like you're gettng confused between using Invoke/BeginInvoke on a windows form/control in a multi-threaded situation, and using Invoke/BeginInvoke on a delegate instance (ie the Asynchornous Programming Model).

This is easy to do as the names are obviously identical, however the scenarios you would use them and their behaviour is different.

The book CLR Via C# gives a good explanation of both types of Invoke/BeginInvoke.

Ash