Ureader.com  
Microsoft software help and Community
   home   |   control panel login   |   archive   |  
 
DotNet
acad.assignment.mngr
academic
adonet
aspnet
aspnet.announcements
aspnet.build.controls
aspnet.caching
aspnet.datagridcontrol
aspnet.mobile
aspnet.security
aspnet.webcontrols
aspnet.webservices
clr
compactframework
component_services
datatools
distributed_apps
drawing
faqs
framework
framework.wmi
general
internationalization
interop
languages.csharp
languages.jscript
languages.vb
languages.vb.controls
languages.vb.data
languages.vb.upgrade
languages.vc
languages.vc.libraries
myservices
odbcnet
performance
remoting
scripting
sdk
security
setup
vjsharp
vsa
webservi.enhancements
webservices
windowsforms
windowsforms.controls
winforms.databinding
winforms.designtime
xml
  
 
date: Tue, 8 Jul 2008 10:25:37 -0500,    group: microsoft.public.dotnet.languages.csharp        back       


Control.BeginInvoke is NOT fire-and-forget   
As much as the CLR team assures us that it's ok to fire-and-forget 
Control.BeginInvoke, it seems it isn't.  Maybe this is a bug.

See for example: the comments in 
http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx

I was encountering a bug that disappeared when debugging.  Not when a 
debugger is attached, mind you, but when I placed a breakpoint near the 
code.  Adding Trace.WriteLine statements showed that the failing code was 
not even being executed.  Ok, what effects can a breakpoint have?  Well, 
evaluation of watch expressions, so I cleared the watch window... check, 
same behavior.  And occasionally (<10%) the code worked even with the 
breakpoint removed or disabled.  Must be a race condition, hitting a 
breakpoint could definitely affect thread scheduling.

Turns out this code (now fixed) was the culprit:

            if (postProcessing != null)
            {
                new UIPermission(UIPermissionWindow.AllWindows).Assert();
                Control c = new Control();
                IntPtr forceHandleCreation = c.Handle;
                MethodInvoker finalProcessing = postProcessing + c.Dispose;
                helper.postProcessing = delegate { 
c.Invoke(finalProcessing); };
            }

            new System.Threading.Thread(helper.UIThreadProc).Start();

The thread procedure:

            public void UIThreadProc()
            {
                new UIPermission(UIPermissionWindow.AllWindows).Assert();
                progressDialog = new 
ProgressTracker((ushort)fileArray.Length, cumulativeSize, actionMsg);
                IntPtr forceHandleCreation = progressDialog.Handle;
                new System.Threading.Thread(WorkThreadProc).Start();
                Application.Run(progressDialog);
                if (postProcessing != null)
                    postProcessing();
            }

I originally had c.BeginInvoke in the asynchronous method.  Seems that if 
you BeginInvoke and then the calling thread ends, the call never takes 
place.  Yuck!

Do you think this is a CLR bug or it is by design?
date: Tue, 8 Jul 2008 10:25:37 -0500   author:   Ben Voigt [C++ MVP] am

RE: Control.BeginInvoke is NOT fire-and-forget   
I can understand why this might happen but I wouldnt think it would be by 
design. 
If it is by design then I guess they expected you to call EndInvoke after 
doing more work or something.

-- 
Ciaran O''Donnell
http://wannabedeveloper.spaces.live.com


"Ben Voigt [C++ MVP]" wrote:

> As much as the CLR team assures us that it's ok to fire-and-forget 
> Control.BeginInvoke, it seems it isn't.  Maybe this is a bug.
> 
> See for example: the comments in 
> http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx
> 
> I was encountering a bug that disappeared when debugging.  Not when a 
> debugger is attached, mind you, but when I placed a breakpoint near the 
> code.  Adding Trace.WriteLine statements showed that the failing code was 
> not even being executed.  Ok, what effects can a breakpoint have?  Well, 
> evaluation of watch expressions, so I cleared the watch window... check, 
> same behavior.  And occasionally (<10%) the code worked even with the 
> breakpoint removed or disabled.  Must be a race condition, hitting a 
> breakpoint could definitely affect thread scheduling.
> 
> Turns out this code (now fixed) was the culprit:
> 
>             if (postProcessing != null)
>             {
>                 new UIPermission(UIPermissionWindow.AllWindows).Assert();
>                 Control c = new Control();
>                 IntPtr forceHandleCreation = c.Handle;
>                 MethodInvoker finalProcessing = postProcessing + c.Dispose;
>                 helper.postProcessing = delegate { 
> c.Invoke(finalProcessing); };
>             }
> 
>             new System.Threading.Thread(helper.UIThreadProc).Start();
> 
> The thread procedure:
> 
>             public void UIThreadProc()
>             {
>                 new UIPermission(UIPermissionWindow.AllWindows).Assert();
>                 progressDialog = new 
> ProgressTracker((ushort)fileArray.Length, cumulativeSize, actionMsg);
>                 IntPtr forceHandleCreation = progressDialog.Handle;
>                 new System.Threading.Thread(WorkThreadProc).Start();
>                 Application.Run(progressDialog);
>                 if (postProcessing != null)
>                     postProcessing();
>             }
> 
> I originally had c.BeginInvoke in the asynchronous method.  Seems that if 
> you BeginInvoke and then the calling thread ends, the call never takes 
> place.  Yuck!
> 
> Do you think this is a CLR bug or it is by design? 
> 
> 
>
date: Tue, 8 Jul 2008 09:07:02 -0700   author:   Ciaran O''Donnell

Re: Control.BeginInvoke is NOT fire-and-forget   
On Tue, 08 Jul 2008 08:25:37 -0700, Ben Voigt [C++ MVP]  
<rbv@nospam.nospam> wrote:

> As much as the CLR team assures us that it's ok to fire-and-forget
> Control.BeginInvoke, it seems it isn't.  Maybe this is a bug.
>
> See for example: the comments in
> http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx
>
> [...]
> Do you think this is a CLR bug or it is by design?

First thing to keep in mind: the assertion about Control.EndInvoke() has  
to do with resource cleanup and whether one is required to call that  
method to ensure things are cleaned up.  It's not about whether  
Control.BeginInvoke() will work.

Second, it would be helpful if you'd actually post a concise-but-complete  
code sample that reliably demonstrates the problem.  Saying "I original  
had c.BeginInvoke in the asynchronous method" doesn't tell us much about  
how you actually used it or what might have been going wrong.

I am relatively confident that if you call BeginInvoke() from a thread  
that exits before the invoked delegate gets to run, the invoked delegate  
should still run.  I would be very surprised if that wasn't actually what  
happened.  On the other hand, if the thread that _owns_ the control being  
used to call BeginInvoke() exits or is otherwise terminated, I would _not_  
expect the delegate being invoked to execute, since it has to execute on  
that thread.

Again, a complete code sample would eliminate these ambiguities in your  
comment.  It's impossible to tell for sure from the code you posted what  
exactly you were trying to do and what broke.  It also doesn't help that  
the code you posted is clearly a corner case, whatever else might have  
been going on, and you didn't post enough to show us that you've correctly  
set the threading model for whatever threads wind up with a message pump  
(something that could also break things).

Given the evidence so far, I cannot imaging being able to confidently say  
there's a bug, whether in the CLR or (as is probably more likely, assuming  
this is a bug at all) in the framework.

Pete
date: Tue, 08 Jul 2008 09:53:28 -0700   author:   Peter Duniho

RE: Control.BeginInvoke is NOT fire-and-forget   
Thanks Pete and Ciaran for your help!

Hi Ben,

The Control.BeginInvoke method executes the specified delegate 
asynchronously on the thread that the control's underlying handle was 
created on. It means that the calling thread doen't need to wait until the 
UI thread finishes processing the request and will returns immediately.

It's true that you should always call a delegate's EndInvoke after a call 
to a delegate's BeginInvoke. It's completely safe to call 
Control.BeginInvoke without ever calling Control.EndInvoke, because it 
doesn't create the same resources associated with a delegate's BeginInvoke 
call.

Even if you do want the results from a call to Control.BeginInvoke, there's 
no way to pass a callback, so you need to use the IAsyncResult 
implementation as returned from Control.BeginInvoke. You keep checking the 
IsCompleted property for true during your other worker thread processing 
before calling Control.EndInvoke to harvest the result. This is such a pain 
that, if you want results from the call to the UI thread, I suggest that 
the worker thread use Control.Invoke instead.

> As much as the CLR team assures us that it's ok to fire-and-forget 
Control.BeginInvoke, it seems it isn't.

Could you please show us a complete code snippet to demonstrate the problem?

I look forward to your reply!

Sincerely,
Linda Liu
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and 
suggestions about how we can improve the support we provide to you. Please 
feel free to let my manager know what you think of the level of service 
provided. You can send feedback directly to my manager at: 
msdnmg@microsoft.com.

==================================================
Get notification to my posts through email? Please refer to 
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues 
where an initial response from the community or a Microsoft Support 
Engineer within 1 business day is acceptable. Please note that each follow 
up response may take approximately 2 business days as the support 
professional working with you may need further investigation to reach the 
most efficient resolution. The offering is not appropriate for situations 
that require urgent, real-time or phone-based interactions or complex 
project analysis and dump analysis issues. Issues of this nature are best 
handled working with a dedicated Microsoft Support Engineer by contacting 
Microsoft Customer Support Services (CSS) at 
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
date: Wed, 09 Jul 2008 07:20:05 GMT   author:   (Linda Liu[MSFT])

Re: Control.BeginInvoke is NOT fire-and-forget   
Peter Duniho wrote:
> On Tue, 08 Jul 2008 08:25:37 -0700, Ben Voigt [C++ MVP]
> <rbv@nospam.nospam> wrote:
>
>> As much as the CLR team assures us that it's ok to fire-and-forget
>> Control.BeginInvoke, it seems it isn't.  Maybe this is a bug.
>>
>> See for example: the comments in
>> http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx
>>
>> [...]
>> Do you think this is a CLR bug or it is by design?
>
> First thing to keep in mind: the assertion about Control.EndInvoke()
> has to do with resource cleanup and whether one is required to call
> that method to ensure things are cleaned up.  It's not about whether
> Control.BeginInvoke() will work.
>
> Second, it would be helpful if you'd actually post a
> concise-but-complete code sample that reliably demonstrates the
> problem.  Saying "I original had c.BeginInvoke in the asynchronous
> method" doesn't tell us much about how you actually used it or what
> might have been going wrong.

Did I write that?  Sure enough.

I should have said "in the anonymous method".

i.e. changing the line from
helper.postProcessing = delegate { c.Invoke(finalProcessing); };
back to
helper.postProcessing = delegate { c.BeginInvoke(finalProcessing); };

breaks things, in that the finalProcessing MulticastDelegate never runs nor 
throws an exception.

>
> I am relatively confident that if you call BeginInvoke() from a thread
> that exits before the invoked delegate gets to run, the invoked
> delegate should still run.  I would be very surprised if that wasn't
> actually what happened.  On the other hand, if the thread that _owns_
> the control being used to call BeginInvoke() exits or is otherwise
> terminated, I would _not_ expect the delegate being invoked to
> execute, since it has to execute on that thread.

The control should be owned by the original thread which does not exit, I 
read the Handle property for the explicit purpose of forcing it to be 
created on that thread, before I spawn the worker.

>
> Again, a complete code sample would eliminate these ambiguities in
> your comment.  It's impossible to tell for sure from the code you
> posted what exactly you were trying to do and what broke.  It also
> doesn't help that the code you posted is clearly a corner case,
> whatever else might have been going on, and you didn't post enough to
> show us that you've correctly set the threading model for whatever
> threads wind up with a message pump (something that could also break
> things).

Changing the call in the asynchronous method which is called at the very end 
of the worker threadproc from BeginInvoke to Invoke does cure the problem. 
I think this demonstrates that the thread on which the control is created is 
properly pumping messages.

>
> Given the evidence so far, I cannot imaging being able to confidently
> say there's a bug, whether in the CLR or (as is probably more likely,
> assuming this is a bug at all) in the framework.

True, it's most likely a bug in the base class libraries, not the CLR.  My 
poor wording.

>
> Pete
date: Wed, 9 Jul 2008 08:41:10 -0500   author:   Ben Voigt [C++ MVP] am

Re: Control.BeginInvoke is NOT fire-and-forget   
Peter Duniho wrote:
> On Tue, 08 Jul 2008 08:25:37 -0700, Ben Voigt [C++ MVP]
> <rbv@nospam.nospam> wrote:
>
>> As much as the CLR team assures us that it's ok to fire-and-forget
>> Control.BeginInvoke, it seems it isn't.  Maybe this is a bug.
>>
>> See for example: the comments in
>> http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx
>>
>> [...]
>> Do you think this is a CLR bug or it is by design?
>
> First thing to keep in mind: the assertion about Control.EndInvoke()
> has to do with resource cleanup and whether one is required to call
> that method to ensure things are cleaned up.  It's not about whether
> Control.BeginInvoke() will work.
>
> Second, it would be helpful if you'd actually post a
> concise-but-complete code sample that reliably demonstrates the
> problem.

I tried and it doesn't reproduce with an unloaded system.  The original 
project has a few other threads of varying priorities doing unrelated tasks 
but certainly affecting thread scheduling and I can definitely understand 
why that can affect the appearance of a race condition.  I'll just use 
Invoke, the thread is dying anyway, it can stay around long enough to get 
the delegate call completed message.
date: Wed, 9 Jul 2008 11:20:08 -0500   author:   Ben Voigt [C++ MVP] am

Re: Control.BeginInvoke is NOT fire-and-forget   
On Wed, 09 Jul 2008 06:41:10 -0700, Ben Voigt [C++ MVP]  
<rbv@nospam.nospam> wrote:

> [...]
>> Again, a complete code sample would eliminate these ambiguities in
>> your comment.  It's impossible to tell for sure from the code you
>> posted what exactly you were trying to do and what broke.  It also
>> doesn't help that the code you posted is clearly a corner case,
>> whatever else might have been going on, and you didn't post enough to
>> show us that you've correctly set the threading model for whatever
>> threads wind up with a message pump (something that could also break
>> things).
>
> Changing the call in the asynchronous method which is called at the very  
> end
> of the worker threadproc from BeginInvoke to Invoke does cure the  
> problem.
> I think this demonstrates that the thread on which the control is  
> created is
> properly pumping messages.

Given the code that was posted, at best it demonstrates that using  
Invoke() treats the call differently than using BeginInvoke().  For  
example, it could be that there's some logic in the Invoke() method that  
winds up calling the delegate on the current thread.

You have all the code, so you can of course make your own judgments.  But  
absent a concise-but-complete code sample, I'm leery of making assumptions  
about what is specifically happening.

The glimpse of the design that we've seen so far makes me think that  
there's probably a much better way to approach whatever you're doing  
anyway.  Creating a dummy Control instance simply for the purpose of  
marshalling execution back to some thread seems very odd to me.  At the  
very least, I'd think a SynchronizationContext would be more appropriate,  
since it wouldn't carry all the extra unused baggage a Control has.  And  
usually, when you actually need code to be marshalled back to a specific  
GUI thread, it's because you have a specific Control instance that  
requires it, and you can just use that instance to do the marshalling (in  
that case, the logic would be moved to whatever code is in your  
"postProcessing" delegate...again, this seems more sensible to me than  
requiring some other code to manage the marshalling arbitrarily).

But, all that said, even if we take as granted that the design is the very  
best approach for managing this, no one here can answer the question as to  
whether there's a bug in the runtime or not.  We don't have all the code,  
and so there's no way to know for sure that it's not just a bug in your  
code.

Personally, I can count on the fingers of one hand with at least one  
finger left over the number of times that someone has said "this is a .NET  
bug" and they wound up being right.  That's in spite of seeing such  
statements many dozens of times.  Granted, I give you a much higher chance  
of being correct on such a statement than the average schmoe, but I'm  
still hesitant to just take the assertion at face value.  I'd want to see  
the code.

But, as long as all you want is for your code to work, I think you've got  
your solution.  Based only on what you've posted, no one can say whether  
it's a .NET bug, but it doesn't sound like that's an important  
consideration for you anyway.

Pete
date: Wed, 09 Jul 2008 09:42:50 -0700   author:   Peter Duniho

Re: Control.BeginInvoke is NOT fire-and-forget   
> The glimpse of the design that we've seen so far makes me think that
> there's probably a much better way to approach whatever you're doing
> anyway.  Creating a dummy Control instance simply for the purpose of
> marshalling execution back to some thread seems very odd to me.  At
> the very least, I'd think a SynchronizationContext would be more
> appropriate, since it wouldn't carry all the extra unused baggage a
> Control has.  And usually, when you actually need code to be
> marshalled back to a specific GUI thread, it's because you have a
> specific Control instance that requires it, and you can just use that
> instance to do the marshalling (in that case, the logic would be
> moved to whatever code is in your "postProcessing" delegate...again,
> this seems more sensible to me than requiring some other code to
> manage the marshalling arbitrarily).


Hmmm.  In Win32, creating a message-only window is a pretty common paradigm. 
And I'm not seeing how SynchronizationContext can help me, at a minimum it 
looks an order of magnitude more complicated to use than Control.Invoke or 
Control.BeginInvoke.  As far as "extra baggage" of a Control, isn't 
cross-thread marshalling dependent on window messages anyway (hence the 
concern for the message loop of the receiving thread), or has .NET conflated 
async calls with the UI message loop?  It sure isn't using the Win32 APC 
mechanism, which would solve the problem nicely with no extra Control needed 
if only the main WinForms message loop did an alertable wait... but it 
doesn't.  I filed a feature request on that over a year ago.

As for why, I'm trying to have my components present a single-threaded event 
driven interface.  Components implemented event-driven with a state machine, 
can fire events directly from their event handlers.  Components that need 
background threads, the thread synchronization code is hidden in the 
implementation where the consumer doesn't ever have to know extra threads 
were created.
date: Wed, 9 Jul 2008 17:30:56 -0500   author:   Ben Voigt [C++ MVP] am

Re: Control.BeginInvoke is NOT fire-and-forget   
On Wed, 09 Jul 2008 15:30:56 -0700, Ben Voigt [C++ MVP]  
<rbv@nospam.nospam> wrote:

> Hmmm.  In Win32, creating a message-only window is a pretty common  
> paradigm.

That's true.  But AFAIK, a Control instance isn't a message-only window.

> And I'm not seeing how SynchronizationContext can help me, at a minimum  
> it
> looks an order of magnitude more complicated to use than Control.Invoke  
> or
> Control.BeginInvoke.

Why?  "SynchronizationContext.Current.Post( /* your delegate here */ );"  
seems simple enough.  For the purpose of your anonymous method, you'll  
probably want to capture the "Current" context for use later.

What about it do you feel is an order of magnitude more complicated?   
Seems to me that creating a whole new Control instance and forcing the  
handle to be created is twice as many lines of code.  :)

> As far as "extra baggage" of a Control, isn't
> cross-thread marshalling dependent on window messages anyway (hence the
> concern for the message loop of the receiving thread), or has .NET  
> conflated
> async calls with the UI message loop?

That I don't know.  The point is that the SynchronizationContext instance  
already exists, so you might as well use it rather than creating a whole  
new Control instance.  :)

> It sure isn't using the Win32 APC
> mechanism, which would solve the problem nicely with no extra Control  
> needed
> if only the main WinForms message loop did an alertable wait... but it
> doesn't.  I filed a feature request on that over a year ago.

Yes, there are still some things in the unmanaged API that would be nice  
to have in .NET.

> As for why, I'm trying to have my components present a single-threaded  
> event
> driven interface.  Components implemented event-driven with a state  
> machine,
> can fire events directly from their event handlers.  Components that need
> background threads, the thread synchronization code is hidden in the
> implementation where the consumer doesn't ever have to know extra threads
> were created.

Personally, I don't mind a design that requires the consumer to know that  
an event or other callback might happen on a different thread.  .NET  
certainly has plenty of examples of that, and they seem to work okay.

Depending on how you expect the thing to be used, you _could_ look at the  
Target for the delegate being invoked to see if it implements  
ISynchronizeInvoke, and then use the Invoke/BeginInvoke on that target for  
the callback.  This of course requires that the delegate be a member of  
the Control sub-class in situations when it must be called on the GUI  
thread.  Obviously there's no way to guarantee that.

Barring that, in this particular situation perhaps SynchronizationContext  
would work for you.  Assuming, of course, I haven't missed something and  
it's not really an order of magnitude more complicated.  I certainly would  
agree that if it takes ten times the code, it might be better to do it  
some other way.  :)

Pete
date: Wed, 09 Jul 2008 22:17:29 -0700   author:   Peter Duniho

Re: Control.BeginInvoke is NOT fire-and-forget   
Peter Duniho wrote:
> On Wed, 09 Jul 2008 15:30:56 -0700, Ben Voigt [C++ MVP]
> <rbv@nospam.nospam> wrote:
>
>> Hmmm.  In Win32, creating a message-only window is a pretty common
>> paradigm.
>
> That's true.  But AFAIK, a Control instance isn't a message-only
> window.
>> And I'm not seeing how SynchronizationContext can help me, at a
>> minimum it
>> looks an order of magnitude more complicated to use than
>> Control.Invoke or
>> Control.BeginInvoke.
>
> Why?  "SynchronizationContext.Current.Post( /* your delegate here */
> );" seems simple enough.  For the purpose of your anonymous method,
> you'll probably want to capture the "Current" context for use later.

Ok, that's not too bad.  An extra anonymous method is required in order to 
make a SendOrPostCallback delegate.  And you must save the Current context. 
So about equal.

I think I just didn't see any example of how to use it.  The documentation 
for that class is beyond horrible.  It starts out by saying "The 
SynchronizationContext class is a base class that provides a free-threaded 
context with no synchronization."  The IsWaitNotificationRequired method 
(shouldn't it be a property?) -- well the method name is more informative 
than the entire documentation page.  And so on, with not a single example 
linked from any of the class members.

>
> What about it do you feel is an order of magnitude more complicated?
> Seems to me that creating a whole new Control instance and forcing the
> handle to be created is twice as many lines of code.  :)
>
>> As far as "extra baggage" of a Control, isn't
>> cross-thread marshalling dependent on window messages anyway (hence
>> the concern for the message loop of the receiving thread), or has
>> .NET conflated
>> async calls with the UI message loop?
>
> That I don't know.  The point is that the SynchronizationContext
> instance already exists, so you might as well use it rather than
> creating a whole new Control instance.  :)
>
>> It sure isn't using the Win32 APC
>> mechanism, which would solve the problem nicely with no extra Control
>> needed
>> if only the main WinForms message loop did an alertable wait... but
>> it doesn't.  I filed a feature request on that over a year ago.
>
> Yes, there are still some things in the unmanaged API that would be
> nice to have in .NET.
>
>> As for why, I'm trying to have my components present a
>> single-threaded event
>> driven interface.  Components implemented event-driven with a state
>> machine,
>> can fire events directly from their event handlers.  Components that
>> need background threads, the thread synchronization code is hidden
>> in the implementation where the consumer doesn't ever have to know
>> extra threads were created.
>
> Personally, I don't mind a design that requires the consumer to know
> that an event or other callback might happen on a different thread. .NET 
> certainly has plenty of examples of that, and they seem to work
> okay.
> Depending on how you expect the thing to be used, you _could_ look at
> the Target for the delegate being invoked to see if it implements
> ISynchronizeInvoke, and then use the Invoke/BeginInvoke on that
> target for the callback.  This of course requires that the delegate
> be a member of the Control sub-class in situations when it must be
> called on the GUI thread.  Obviously there's no way to guarantee that.
>
> Barring that, in this particular situation perhaps
> SynchronizationContext would work for you.  Assuming, of course, I
> haven't missed something and it's not really an order of magnitude
> more complicated.  I certainly would agree that if it takes ten times
> the code, it might be better to do it some other way.  :)
>
> Pete
date: Thu, 10 Jul 2008 09:00:04 -0500   author:   Ben Voigt [C++ MVP] am

Re: Control.BeginInvoke is NOT fire-and-forget   
>> As far as "extra baggage" of a Control, isn't
>> cross-thread marshalling dependent on window messages anyway (hence
>> the concern for the message loop of the receiving thread), or has
>> .NET conflated
>> async calls with the UI message loop?
>
> That I don't know.  The point is that the SynchronizationContext
> instance already exists, so you might as well use it rather than
> creating a whole new Control instance.  :)

Well, to answer whether window messages are used for SynchronizationContext, 
I can tell you (from Reflector), that WindowsFormsSynchronizationContext is 
implemented on top of Control.Invoke and Control.BeginInvoke.

Also, Control.MarshaledInvoke (the underlying implementation of Invoke and 
BeginInvoke) does use a windows message to notify the target thread.  The 
delegate itself is not passed using the message data (as far as I know you 
can't safely pass addresses of garbage collectable objects asynchronously --  
ok, yes you can with GCHandle).  And Invoke-ing a delegate on your own 
thread looks like it causes all invokes you've received from other threads 
to be processed immediately instead of waiting for the message loop. 
There's explicit locking everywhere and I'm glad I came up with my own 
solution for my C++/CLI IO components (where all requests are actually 
processed with APCs on a native thread running an alertable wait loop). 
Maybe I need to think about using that lockless message queue to pass 
delegates and make my own SynchronizationContext implementation -- but since 
I don't control the message loop it wouldn't be nearly as elegant.
date: Thu, 10 Jul 2008 09:13:28 -0500   author:   Ben Voigt [C++ MVP] am

Google
 
Web ureader.com


    COPYRIGHT 2007, YARDI TECHNOLOGY LIMITED, ALL RIGHT RESERVE  |   contact us