BeginInvoke()..does it involve the message queue?

  • Thread starter Thread starter MSDN
  • Start date Start date
M

MSDN

Hello,

Can anyone explain to me the specifics of how Control.BeginInvoke() is
implemented? Coming from a java background I expected it to behave somewhat
like SwingUtilities.invokeLater(). That is to say, I expected it append a
'unit of work' to the end of the message queue in a thread-safe fashion.

The problem is that I can't explain why the following code makes the entire
UI freeze. It appears that the infinite loop of BeginInvoke() methods is
preventing all other events (paint, etc) from being processed.


Form2.cs
public void Callback()
{
Debug.WriteLine("Callback #" + count++);
this.BeginInvoke( new MethodInvoker(this.Callback) );
}

Form1.cs
private void launchForm__Click(object sender, System.EventArgs e)
{
Form2 tmp = new Form2();
tmp.Visible = true;
tmp.Callback();
}

Is there an alternative to BeginInvoke() that would make this example work,
allowing the UI to paint and otherwise respond albeit still consuming
excessive CPU cycles? Does Control.BeginInvoke() have nothing to do with
the message queue?

I would appreciate any specific details of the Control.BeginInvoke()
implementation. "Executes the specified delegate asynchronously with the
specified arguments, on the thread that the control's underlying handle was
created on" is too ambiguous for me.

Thanks.

Darryl
 
MSDN said:
Can anyone explain to me the specifics of how Control.BeginInvoke() is
implemented? Coming from a java background I expected it to behave somewhat
like SwingUtilities.invokeLater(). That is to say, I expected it append a
'unit of work' to the end of the message queue in a thread-safe fashion.

The problem is that I can't explain why the following code makes the entire
UI freeze. It appears that the infinite loop of BeginInvoke() methods is
preventing all other events (paint, etc) from being processed.

And so it should! Using BeginInvoke doesn't have any effect in this
case, as you're already running within the UI thread.

Is there an alternative to BeginInvoke() that would make this example work,
allowing the UI to paint and otherwise respond albeit still consuming
excessive CPU cycles? Does Control.BeginInvoke() have nothing to do with
the message queue?

If you want the UI thread to run separately to your work, you don't
want to use Control.Invoke - that does the opposite to what you want,
*forcing* the callback to be made in the UI thread, even if you were
previously running in the non-UI thread.

Just creating a new thread to do the work would do the trick - or you
could use delegate.BeginInvoke, or the ThreadPool.
I would appreciate any specific details of the Control.BeginInvoke()
implementation. "Executes the specified delegate asynchronously with the
specified arguments, on the thread that the control's underlying handle was
created on" is too ambiguous for me.

Which particular bit of it?
 
Hi,
Can anyone explain to me the specifics of how Control.BeginInvoke() is
implemented? Coming from a java background I expected it to behave somewhat
like SwingUtilities.invokeLater(). That is to say, I expected it append a
'unit of work' to the end of the message queue in a thread-safe fashion.

The problem is that I can't explain why the following code makes the entire
UI freeze. It appears that the infinite loop of BeginInvoke() methods is
preventing all other events (paint, etc) from being processed.

The real reason why this particular application freezes is because it
enters in infinite kind of recursion. Actually is more like infinte loop.
And as long as the delegate is executed in the main UI thread the programm
cannot proccess other events.
Is there an alternative to BeginInvoke() that would make this example work,
allowing the UI to paint and otherwise respond albeit still consuming
excessive CPU cycles? Does Control.BeginInvoke() have nothing to do with
the message queue?

I believe Control.Invoke and Control.EndInvoke have ineed something to do
with the windows message queue.
Actually, the message which is posted is called
"WindowsForms11_ThreadCallbackMessage".
Delegate.BeginInvoke doesn't use any messages, though. The latter is what
you might want to use.

I would appreciate any specific details of the Control.BeginInvoke()
implementation. "Executes the specified delegate asynchronously with the
specified arguments, on the thread that the control's underlying handle was
created on" is too ambiguous for me.

Actually this is more or less what PostMessage (which is used internally in
the realization) do.

I found the MSDN page for this method kind of fuzzy. I can't understand what
the following means:

" ...Note: The BeginInvoke method calls the specified delegate back on a
different thread pool thread. You should not block a thread pool thread for
any length of time..."

Isn't it totaly wrong?

B\rgds
100
 
This example is definitely concocted. The example intentially created an
infinite loop for the purposes of investigation. I'm still puzzled by the
behaviour.

My understanding of things is:

1. Control.BeginInvoke() causes some sort of message (XXX) to be posted to
the UI event message queue. I would expect this operation to be an
"enqueue". In other words, I wouldn't expect XXX events to take priority or
somehow preceed all other pending UI events (paint, etc).
Control.BeginInvoke is safe to call from any thread including the UI thread.
All that means too me is that the access to the UI event queue is
synchronized.

2. The Control.BeginInvoke() caller proceeds once XXX is posted, regardless
of whether the caller is the UI thread or another thread. If the UI thread
is the caller, the UI thread will continue and eventually return to the UI
event loop.

3. The UI message pump will process all events in the event queue in order.
Any normal events that were pending will be done as normal. Paint, Mouse,
etc events will all be processed in order as normal. The XXX event has not
yet been processed.

3. The UI message pump encounters an XXX event and processes it in an
event-specific manner as any other event is processed. In this case, XXX
events are processed by executing the Callback() method.

4. The Callback() method does another Control.BeginInvoke() (the infinite
loop portion of this example)...which will eventually lead back to #1.

If the summary above is correct, then I would expect my "infinite loop"
example to still leave room for other UI events to be queued/processed.

What am I missing?
 
3. The UI message pump will process all events in the event queue in
order.
Any normal events that were pending will be done as normal. Paint, Mouse,
etc events will all be processed in order as normal. The XXX event has not
yet been processed.
Actually, few of the messages received by an application are posted. Most of
the are sent. Posted messages are those coming from the user input
(keyboard, mouse as well as WM_PAINT, WM_TIMER, WM_QUIT) and any explicitly
posted messages by the applications. However WM_PAINT, WM_TIMER, WM_QUIT are
not real messages. Rather they are flags in the message queue structure and
the messages are synthesized for the GetMessage and PeekMessage functions.
They are very low priority messages. WM_QUIT is the lowest priorty message,
WM_PAINT will be returned only of there is no other messages pending in the
message queue.

Windows message queue has separate queue for the sent messages. Yes, some of
the sent messages goes thru the windows message queue and those are messages
which are sent from a different thread. And this is likely the case with the
system messages. So the order how the PeekMessage and GetMessage normaly
process messages is:
Sent messages
Posted messages
Input (hardware) messages and system internal events
Sent messages (again)
WM_PAINT messages
WM_TIMER messages

However this order can be changed if GetMessage and PeekMessage explicitly
specify which types of messages is to be retreived from the queue. The those
messages will be processed even before the sended messages.

This is likely the case with the message with the BeginInvoke. I think
WindowsForms message loop has logic inside to look firstly for messages for
async called events (ant this make sense to me).
This is the reason I believe why the application freeze in your case.

HTH
B\rgds
100
 
Hi "100",

Thanks for your replies. They provided the type of in-depth insight that I
was seeking. If you are aware of *.net-relevant* books that I could consult
for future low-level questions such as this I would appreciate the
recommendations.

Regards,

Darryl
 
Hi Darryl,
Actually this is more Windows relevant than .NET. As long as .NET is build
over the existing windows platform (almost the same old story of Win 3.1 and
MS-DOS) most of the Win32 releated things are still valid. What we have to
do is to find what .NET functionallity which Win32 one exploits. Of course
no one should count on them when writting programs. Those are internals for
the framework and are subject to change even in the next service pack.
However, if you haven't read Jeffrey Richter's "Advanced Windows 3rd
editrion" yet, take a look on this book. You can find tons of windows (not
..NET ) internals there. You can find almost all about processes and threads
(priorities, CPU scheduling, etc), memory management, all that I told you
about messages and message dispatching and more good stuff.
About .NET internals I'll recomend you again Jeffrey Richter's book "Applied
Microsoft .NET Framework Programming", the articles of the same author in
the MSDN magazine as well as Don Box' "Essential .NET". These are the best
sources about .NET internals I've found so far.
And of course exploring the ROTOR's source code, which unfortunately I
haven't had time to do yet.

HTH
B\rgds
100
 
Back
Top