Question about BeginInvoke.

J

Jason Kendall

I don't understand why the order of events happening here is
predictable.


Let's say I have a base class user control with a 'Load' event handler
and a sub:
Private Sub iMatterControlForm_Load(ByVal sender As Object, ByVal e
As System.EventArgs) Handles Me.Load
Debug.WriteLine("BASE CLASS LOAD")
Me.BeginInvoke(New MethodInvoker(AddressOf TestOnLoad))
End Sub

Private Sub TestOnLoad()
Debug.WriteLine("ON LOAD Base Class")
End Sub

I then have a class which inherits from the base which takes a long
time to execute.

Private Sub MatterProfile_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
Debug.WriteLine("BEFORE SLEEP SUB Class")
System.Threading.Thread.Sleep(5000)
Debug.WriteLine("After Seep SUB Class")
End Sub


Now, I am pretty sure that calling 'BeginInvoke' calls the delegate on
a ThreadPool thread. So, to my ignorant mind, I would expect my
output window to show something like this, with a possible race
condition flip flopping the middle two statements.
BASE CLASS LOAD
BEFORE SLEEP SUB Class
ON LOAD Base Class
AfterSleep SUB Class

In fact what always happens is that I see the following:
BASE CLASS LOAD
BEFORE SLEEP SUB Class
AfterSleep SUB Class
ON LOAD Base Class

So, it looks to me like there's an execution stack (or something) that
has the base Load event and the subclass Load event already stacked up
and the ThreadPool cannot start executing the TestOnLoad method until
the other two functions are executed off of the stack.

Can one of you bright people out there explain what's happening here?
I trust my results, but I'd MUCH rather understand the 'why'.

Thanks!
 
P

Peter Duniho

Now, I am pretty sure that calling 'BeginInvoke' calls the delegate on
a ThreadPool thread. [...]

So, it looks to me like there's an execution stack (or something) that
has the base Load event and the subclass Load event already stacked up
and the ThreadPool cannot start executing the TestOnLoad method until
the other two functions are executed off of the stack.

Can one of you bright people out there explain what's happening here?
I trust my results, but I'd MUCH rather understand the 'why'.

Well, assuming that your code is actually within the Form instance, then
the reason you're seeing what you're seeing is that you're wrong about
your assumption "that calling 'BeginInvoke' calls the delegate on a
ThreadPool thread".

One of the few things that really annoys me about the design of .NET is
the use of the same word to describe two fundamentally different things.
In this case, you're calling the Control.BeginInvoke() method, not the
Delegate.BeginInvoke() method. In the latter case, it would indeed
execute on a ThreadPool thread. However, in the former case the
invocation is queued on the Control's message queue and always executed on
the thread that owns that Control.

In your case, the Control is the Form, and you will never execute the
delegate until the current handler has exited and returned control to the
message pump. So the BeginInvoke() called in the base class will never
get executed until all of the Load event handlers are finished.

(Another area where the same term is used to describe two completely
different things is "events". A class can have an event, which allows
delegates to be subscribed, and of course there are also events that you
can wait on, as a synchronization mechanism)

Pete
 
J

Jon Skeet [C# MVP]

Now, I am pretty sure that calling 'BeginInvoke' calls the delegate on
a ThreadPool thread.

No. The whole point of Control.Invoke/BeginInvoke is to call the
delegate on the UI thread responsible for that control.

I suspect you're getting confused with calling BeginInvoke *on* a
delegate, which does indeed use a ThreadPool thread.
 
J

Jason Kendall

Holy smokes, this is such a good explanation.

Thanks so much!

--
Jason Kendall
(e-mail address removed)



Now, I am pretty sure that calling 'BeginInvoke' calls the delegate on
a ThreadPool thread. [...]

So, it looks to me like there's an execution stack (or something) that
has the base Load event and the subclass Load event already stacked up
and the ThreadPool cannot start executing the TestOnLoad method until
the other two functions are executed off of the stack.

Can one of you bright people out there explain what's happening here?
I trust my results, but I'd MUCH rather understand the 'why'.

Well, assuming that your code is actually within the Form instance, then
the reason you're seeing what you're seeing is that you're wrong about
your assumption "that calling 'BeginInvoke' calls the delegate on a
ThreadPool thread".

One of the few things that really annoys me about the design of .NET is
the use of the same word to describe two fundamentally different things.
In this case, you're calling the Control.BeginInvoke() method, not the
Delegate.BeginInvoke() method. In the latter case, it would indeed
execute on a ThreadPool thread. However, in the former case the
invocation is queued on the Control's message queue and always executed on
the thread that owns that Control.

In your case, the Control is the Form, and you will never execute the
delegate until the current handler has exited and returned control to the
message pump. So the BeginInvoke() called in the base class will never
get executed until all of the Load event handlers are finished.

(Another area where the same term is used to describe two completely
different things is "events". A class can have an event, which allows
delegates to be subscribed, and of course there are also events that you
can wait on, as a synchronization mechanism)

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top