EndInvoke still required?

  • Thread starter Thread starter Erik Funkenbusch
  • Start date Start date
E

Erik Funkenbusch

I've read a lot of comments from the 1.1 framework era about a page of the
documentation that claims you have to always call EndInvoke on an
IAsynchResult.

Various comments I've read suggest that this wasn't strictly required in
the current implementation (1.0 and probably 1.1) but that the runtime team
reserved the right to leak if you didn't call EndInvoke.

I've been looking through the 2.0, 3.0, and 3.5 documentation and can no
longer find this reference. The Asynchronous Programming Overview page no
longer says anything about this being a requirement, and the BeginInvoke
method doesn't mention anything about it.

Is EndInvoke still a requirement? I've read elsewhere that the the
framework team has guarnateed that BeginInvoke won't leak, so it's a bit
confusing.
 
Hello Erik,

And what about the result? How do u know if it was successful or not?

---
WBR,
Michael Nemtsev [.NET/C# MVP] :: blog: http://spaces.live.com/laflour

"The greatest danger for most of us is not that our aim is too high and we
miss it, but that it is too low and we reach it" (c) Michelangelo


EF> Various comments I've read suggest that this wasn't strictly
EF> required in the current implementation (1.0 and probably 1.1) but
EF> that the runtime team reserved the right to leak if you didn't call
EF> EndInvoke.
EF>
 
You would be better off calling EndInvoke. If the method returns some
unmanaged data, while it will not "leak" memory per se, the memory may be
retained until the application is terminated. Unmanaged memory is always
released when the application terminates, so there is no real memory leaking
going on. But it is possible that some unmanaged memory may remain allocated
until the app terminates. I cannot be sure, but calling EndInvoke is not a
big deal, particularly if you don't care about the return value.

--
HTH,

Kevin Spencer
Chicken Salad Surgeon
Microsoft MVP
 
Hello Erik,

And what about the result? How do u know if it was successful or not?

Obviously, I am not concerned about any result.

This is known as "fire and forget".

Here's my situation. I am doing asynchronous socket receives via
Socket.BeginUpdate. When I receive a block of data, I want to fire off a
command to to the form to update itself.

Because the asynchronous socket runs in a background thread, and I don't
want to block any of the I/O thread pool, I want to call the forms
BeginInvoke method to force it to execute the function (which takes no
arguments and returns no values) on the GUI thread.

However, if I have to call EndInvoke on the function, from the thread that
created it, then i have to block my I/O update thread.

There are a number of other ways to handle this problem, but they're all
more complex and less elegant than a simple "fire and forget" BeginInvoke
call.
 
You would be better off calling EndInvoke. If the method returns some
unmanaged data, while it will not "leak" memory per se, the memory may be
retained until the application is terminated. Unmanaged memory is always
released when the application terminates, so there is no real memory leaking
going on. But it is possible that some unmanaged memory may remain allocated
until the app terminates. I cannot be sure, but calling EndInvoke is not a
big deal, particularly if you don't care about the return value.

The method does not return any data. It has no parameters, and returns
void.

I am aware of what a memory leak means. The application can run for many
days, weeks, or even months at a time without restarting. As such, I am
concered about memory that is not garbage collected building up and causing
a continual drain on resources, especially since I might fire off one of
these asynch method calls several times per minute or more.

Even if the current framework doesn't leak memory, i'm concerned with
statements I read that the runtime team reserves the right leak if
EndInvoke is not called, but those statements were from around 2003. I
have not read anything about this with the 2.0 framework or greater, and I
couldn't find the requirement to call EndInvoke in the SDK documentation
that used to be there in 1.1.

That's why I'm asking if this requirement is still present.
 
[...]
There are a number of other ways to handle this problem, but they're all
more complex and less elegant than a simple "fire and forget" BeginInvoke
call.

In a previous thread, Jon Skeet mentioned that he believed that the .NET
team had at some point stated that they guaranteed that calling
Control.BeginInvoke() without a matching call to Control.EndInvoke() would
_not_ leak resources. I am personally very nervous about not calling
EndInvoke(), but for this particular case you're right that it's not as
convenient as it could be to do so, and I have been using
Control.BeginInvoke() without a matching EndInvoke() call without any
problems.

I would feel _much_ better about doing that if there were some explicit
statement in the official documentation regarding the situation. I have
not even seen any unofficial statement along these lines (like whatever
one Jon was referencing).

For other examples of the async interface that I've used, there's always
an option to provide a callback and I always match with an EndXXX call in
that callback. But because Control.BeginInvoke() provides no mechanism
for being explicitly notified via a callback _after_ the operation has
completed, I just take the easy way out and trust that it won't leak if I
don't call EndInvoke(). One could without too much difficulty write code
that would deal with the situation by calling EndInvoke(), but it would
still complicate the code and probably unnecessarily.

Pete
 
[...]
There are a number of other ways to handle this problem, but they're all
more complex and less elegant than a simple "fire and forget" BeginInvoke
call.

In a previous thread, Jon Skeet mentioned that he believed that the .NET
team had at some point stated that they guaranteed that calling
Control.BeginInvoke() without a matching call to Control.EndInvoke() would
_not_ leak resources.

I read that as well, which is why I'm a bit confused about the current
status of this.
I am personally very nervous about not calling
EndInvoke(), but for this particular case you're right that it's not as
convenient as it could be to do so, and I have been using
Control.BeginInvoke() without a matching EndInvoke() call without any
problems.

I'm glad to hear that. Have you measured this somehow? Has your
application been long-running?
I would feel _much_ better about doing that if there were some explicit
statement in the official documentation regarding the situation. I have
not even seen any unofficial statement along these lines (like whatever
one Jon was referencing).

As would I.
For other examples of the async interface that I've used, there's always
an option to provide a callback and I always match with an EndXXX call in
that callback. But because Control.BeginInvoke() provides no mechanism
for being explicitly notified via a callback _after_ the operation has
completed, I just take the easy way out and trust that it won't leak if I
don't call EndInvoke(). One could without too much difficulty write code
that would deal with the situation by calling EndInvoke(), but it would
still complicate the code and probably unnecessarily.

Hmm.. Am I reading you correctly? You can call the EndInvoke from another
thread? (specifically the thread that gets used for the Inovke?). That
would make things significantly easier. I was under the impression you had
to call the EndInvoke from the thread that issued the BeginInvoke.

One idea I was tossing around was to store the IAsyncResults in a list, and
every time my Receive callback gets called, walk the list and check for
IsCompleted, then call EndInvoke on all the completed results, which
shouldn't unduly burden the IO thread. However, I was concerned that
calling EndInvoke from a (probably) different IO pool thread than the one
that invoked it was not allowed.

If you are allowed to call EndInvoke from any thread, then my solution
seems like an unduly complicated or burdensome solution, even if in
practice it never really is a problem.
 
The unofficial statement is on Chris Brumme's blog, in some of the
comments:

http://blogs.gotdotnet.com/cbrumme/archive/2003/05/06/51385.aspx

The also deals with EndXXX in general.

Excellent news. Chris Brumme says it's "the official word". So
Control.BeginInvoke is a different beast from any other asyncronous method
used in the framework. That makes sense, given it's lack of completion
callback, they have to make a special exception for this use.
 
The unofficial statement is on Chris Brumme's blog, in some of the
comments:

http://blogs.gotdotnet.com/cbrumme/archive/2003/05/06/51385.aspx

The also deals with EndXXX in general.

Thanks for the link. To sum up:

* For examples of BeginXXX that follow the standard .NET convention,
calling EndXXX is definitely important
* For Control.BeginInvoke(), which does not follow the standard .NET
convention, almost five years ago someone from the WinForms team stated
that you do _not_ need to call Control.EndInvoke()

It's nice to see in print, but it seems like they've had plenty of time to
incorporate this advice into the documentation (and even in that
unofficial reference there wasn't anything that actually said this
behavior is future-proof). I guess it's time to file a complaint on the
docs. One way or the other, the valid behavior needs to be explicitly
described in the official docs.

Thanks,
Pete
 
It's nice to see in print, but it seems like they've had plenty of time to
incorporate this advice into the documentation (and even in that
unofficial reference there wasn't anything that actually said this
behavior is future-proof). I guess it's time to file a complaint on the
docs. One way or the other, the valid behavior needs to be explicitly
described in the official docs.

I agree 100%. I'm not sure how we go about filing a complaint on this,
though. Any ideas?
 
I read that as well, which is why I'm a bit confused about the current
status of this.

Frankly, I'm still confused. I appreciate the link Jon provided, but it's
ancient in industry time. I've submitted a comment on the
Control.BeginInvoke() doc page, referencing the blog and pointing out that
the information really needs to be explicit in the docs one way or the
other.
I'm glad to hear that. Have you measured this somehow? Has your
application been long-running?

Nope...I've taken a head-in-the-sand approach. Sorry I can't offer more
confident information, but I've just trusted that it's not a problem. So
far, it hasn't been. I certainly haven't done any explicit
stress-testing, though at least one application uses Control.BeginInvoke()
to do UI updates for network i/o.
Hmm.. Am I reading you correctly? You can call the EndInvoke from
another
thread? (specifically the thread that gets used for the Inovke?). That
would make things significantly easier. I was under the impression you
had
to call the EndInvoke from the thread that issued the BeginInvoke.

Well, yes and no.

I'm aware of no restriction on what thread calls EndXXX. For sure,
there's no such restriction for the usual models, since normally you call
at least one BeginXXX on the UI thread and the EndXXX is called in a
callback that is executing on a thread pool thread. I believe there's no
restriction for Control.EndInvoke() either.

But you can't call Control.EndInvoke() from the code (as opposed to the
thread) that is itself invoked, at least it doesn't seem to me that you
can. Control.EndInvoke() should not complete until the method that was
invoked has returned. So if you call Control.EndInvoke() from within that
method, it should block waiting for your method to complete, which will
never happen because it's blocked on the call to Control.EndInvoke().

I admit, I haven't actually tried to write that code. But the comment for
that blog entry that raised the whole Control.BeginInvoke() question in
the first place described the exact same issue. It does seem reasonable
to me that one should not expect Control.EndInvoke() to return until the
operation has actually completed.

So, sure...you can call Control.EndInvoke() from the UI thread. But not
from the invoked method running on the UI thread, because that would
deadlock.
One idea I was tossing around was to store the IAsyncResults in a list,
and
every time my Receive callback gets called, walk the list and check for
IsCompleted, then call EndInvoke on all the completed results, which
shouldn't unduly burden the IO thread. However, I was concerned that
calling EndInvoke from a (probably) different IO pool thread than the one
that invoked it was not allowed.

I don't think that would be a problem, and I think that doing it that way
would get you most of the way there. Note, however, that it assumes that
there will always be a receive callback occurring after a call to
Control.BeginInvoke().

This would be true most of the time, but at some point you're going to
have the last receive callback that occurs. This will presumably call
BeginInvoke() still, and there will never be another receive callback to
provide the opportunity to call EndInvoke().

Other solutions would be similar, involving a queue processed somewhere.
You could put a timer on the Form, or run a dedicated consumer thread.
These should all be able to process _all_ of the EndInvokes() necessary.

Even more convoluted, you could use the Delegate async methods
BeginInvoke() and EndInvoke(), which _do_ provide a callback (so you can
easily clean those up). You could use the asynchronously invoked delegate
either to call Control.EndInvoke(), or even just to call Control.Invoke()
directly (avoiding the entire Control.Begin/EndInvoke() issue altogether
:) ).

It's not impossible to ensure that Control.EndInvoke() is called, but it
sure as heck is inconvenient. :) That's why I've just taken the lazy way
out and assumed that the statements are true and common-sense prevails
here.

Pete
 
I agree 100%. I'm not sure how we go about filing a complaint on this,
though. Any ideas?

I don't know about how you're looking at the docs, but for me I just click
on the "Click to Rate and Give Feedback" link at the top of the page.

In the past I've also used the "Give MSDN Web site feedback" link found on
the "Contact Us" page (there's a link on the bottom of each doc page).
For me, that link is:
<https://support.microsoft.com/contactus2/emailcontact.aspx?scid=sw;en;1255&ws=msdn&sd=msdn&pa=msdnw>

Either means of communicating to them seems reasonable. I don't know for
sure that it works, never having received a reply, but I do know that at
least one example of a doc page I complained about, when I checked it
again later they had fixed the problem.

Pete
 
Frankly, I'm still confused. I appreciate the link Jon provided, but it's
ancient in industry time. I've submitted a comment on the
Control.BeginInvoke() doc page, referencing the blog and pointing out that
the information really needs to be explicit in the docs one way or the
other.

I've also submitted an email to someone that used to be on the Windows
Forms team, and asked if they could forward it to the appropriate person on
the WF team, asking if this information was correct, if it was guaranteed,
and if the docs could be updated.
I'm aware of no restriction on what thread calls EndXXX. For sure,
there's no such restriction for the usual models, since normally you call
at least one BeginXXX on the UI thread and the EndXXX is called in a
callback that is executing on a thread pool thread. I believe there's no
restriction for Control.EndInvoke() either.

That's a relief. I'm not sure where I got that idea. Now that you mention
it this way, i've seen a number of examples do exactly that.
But you can't call Control.EndInvoke() from the code (as opposed to the
thread) that is itself invoked, at least it doesn't seem to me that you
can. Control.EndInvoke() should not complete until the method that was
invoked has returned. So if you call Control.EndInvoke() from within that
method, it should block waiting for your method to complete, which will
never happen because it's blocked on the call to Control.EndInvoke().

Yes, I was aware of that. I wasn't particularly clear. I agree, most
likely a deadlock condition.
This would be true most of the time, but at some point you're going to
have the last receive callback that occurs. This will presumably call
BeginInvoke() still, and there will never be another receive callback to
provide the opportunity to call EndInvoke().

Yes, I would obviously have to deal with this situation in some application
cleanup code. However, since the application would be ending anyways, i'm
not sure it's that important to clean up, other than for neatnesses sake.
Other solutions would be similar, involving a queue processed somewhere.
You could put a timer on the Form, or run a dedicated consumer thread.
These should all be able to process _all_ of the EndInvokes() necessary.

The timer would just use unnecessary resources, running when it didn't have
to. And creating a consumer thread for this one purpose seems wasteful as
well.
Even more convoluted, you could use the Delegate async methods
BeginInvoke() and EndInvoke(), which _do_ provide a callback (so you can
easily clean those up). You could use the asynchronously invoked delegate
either to call Control.EndInvoke(), or even just to call Control.Invoke()
directly (avoiding the entire Control.Begin/EndInvoke() issue altogether
:) ).

This is a good solution actually. I see it as less convoluted and less
resource wasteful (since the delegate async threads will come from the app
worker thread pool). It could be packed up into a helper class, quite
easily and far less prone to maintenance errors. But, as you say, still
more work than is strictly necessary if Control.EndInvoke is guaranteed to
not be needed.
It's not impossible to ensure that Control.EndInvoke() is called, but it
sure as heck is inconvenient. :) That's why I've just taken the lazy way
out and assumed that the statements are true and common-sense prevails
here.

All non-trivial programming has inherant risk. I mean, how often of us
really check for memory allocation exceptions everywhere we use them? ;)
 
[...]
This would be true most of the time, but at some point you're going to
have the last receive callback that occurs. This will presumably call
BeginInvoke() still, and there will never be another receive callback to
provide the opportunity to call EndInvoke().

Yes, I would obviously have to deal with this situation in some
application
cleanup code. However, since the application would be ending anyways,
i'm
not sure it's that important to clean up, other than for neatnesses sake.

Well, it depends on the resources being used. It does seem like in the
case of Control.BeginInvoke(), no resources that have external effects
would be involved and that just ignoring the cleanup would be fine.

Of course, since we've already seen reasonably good information suggesting
cleaning up is unnecessary in any case, it seems odd to be even talking
about under what _other_ situation cleanup might or might not be optional.
The timer would just use unnecessary resources, running when it didn't
have
to. And creating a consumer thread for this one purpose seems wasteful
as
well.


This is a good solution actually. I see it as less convoluted and less
resource wasteful (since the delegate async threads will come from the
app
worker thread pool).

I don't see this as any less wasteful than using a timer or another
thread. The timer in particular should be reasonably low impact, since it
takes advantage of the built-in WM_TIMER mechanism. You don't even need a
new thread to service the timer, and your GUI thread needs to be
processing events every now and then anyway. A single extra consumer
thread isn't really that big of a deal, and it's not like queuing
something on the thread pool is completely cost-free (also, using the
thread pool exposes your code to congestion in the thread pool, something
that Control.BeginInvoke() wouldn't otherwise have to worry about).

In other words, I don't think any of the solutions are _especially_
wasteful, and I don't see using the thread pool via Delegate-async
mechanisms is obviously better, even though I think that all of the
possibly solutions are probably pointless. :)
It could be packed up into a helper class, quite
easily and far less prone to maintenance errors. But, as you say, still
more work than is strictly necessary if Control.EndInvoke is guaranteed
to
not be needed.

Exactly.

Pete
 
I don't see this as any less wasteful than using a timer or another
thread. The timer in particular should be reasonably low impact, since it
takes advantage of the built-in WM_TIMER mechanism. You don't even need a
new thread to service the timer, and your GUI thread needs to be
processing events every now and then anyway.

Timers are one of my pet peeves. I've seen one too many application where
people just punt and put stuff in timers. Timers are always a last resort
in my book, unless you absolutely need to do something ever so often. It's
polling, basically, and polling is wasteful.

The whole idea of event driven programing is that you're only doing work
when it's necessary to do so. Waking up the process when it's not needed
causes more CPU cycles to be executed, more heat generated, more wasted
battery power on laptops, etc...

Yes, you can argue that there's probably other stuff going to happen
anyways, so it's not a big deal, but that's the kind of thinking that leads
to everyone stuffing their own taskbar icons down by your clock, or popping
up windows on top of everything else. I refuse to be a part of the problem
;)
A single extra consumer
thread isn't really that big of a deal, and it's not like queuing
something on the thread pool is completely cost-free (also, using the
thread pool exposes your code to congestion in the thread pool, something
that Control.BeginInvoke() wouldn't otherwise have to worry about).

Using the worker pool is likely to not create a new thread. It will
already be there and in the pool. You're right that you have to consider
congestion, but in a relatively low performing app, it's not really a
concern. Certainly, i'd take a consumer thread over a timer any day,
especially when this is something that can be waited on rather than polled.
In other words, I don't think any of the solutions are _especially_
wasteful, and I don't see using the thread pool via Delegate-async
mechanisms is obviously better, even though I think that all of the
possibly solutions are probably pointless. :)

Good point.
 
Timers are one of my pet peeves. I've seen one too many application
where
people just punt and put stuff in timers. Timers are always a last
resort
in my book, unless you absolutely need to do something ever so often.
It's
polling, basically, and polling is wasteful.

I don't disagree per se, except for perhaps the "last resort" comment.
There are in fact situations in which a timer is actually an appropriate
solution. They aren't necessarily indicative of poor design.
The whole idea of event driven programing is that you're only doing work
when it's necessary to do so. Waking up the process when it's not needed
causes more CPU cycles to be executed, more heat generated, more wasted
battery power on laptops, etc...

Well, my point (as you noted) is that a WM_TIMER is often not going to be
waking a thread up anyway. In any case, in this situation _some_ thread
needs to be working on the problem. The real risk is having the timer
wake up and there not be anything to do, but that is solveable (if nothing
else, you can just disable the timer unless you've got something in your
queue).
Yes, you can argue that there's probably other stuff going to happen
anyways, so it's not a big deal, but that's the kind of thinking that
leads
to everyone stuffing their own taskbar icons down by your clock, or
popping
up windows on top of everything else. I refuse to be a part of the
problem
;)

I'm not sure I see the connection, but okay.
Using the worker pool is likely to not create a new thread. It will
already be there and in the pool.

Whether it has to create the thread or not, there's a cost involved in
queueing a delegate for execution on the worker thread, and then allowing
that thread to run, executing your code.

My comment about "cost-free" was not intended to be limited just to the
cost of creating a new thread. There are always other costs as well.
You're right that you have to consider
congestion, but in a relatively low performing app, it's not really a
concern. Certainly, i'd take a consumer thread over a timer any day,
especially when this is something that can be waited on rather than
polled.

Well, in a relatively low-performing app, who cares whether the most
efficient algorithm is being used? You should select the algorithm that
leads to the simplest, easiest-to-maintain code.

And in a high-throughput app, you'd better be testing different algorithms
in real-world cases, to measure performance yourself, rather than making
assumptions about what's more efficient and what's not.

In other words, I still don't see any reason that one approach should be
considered obviously more efficient than the other. I don't find the
differences obvious myself, and there are reasons other than efficiency
for selecting one mechanism over another (granted, these are somewhat
subjective in nature, but that doesn't make them any less important).

Pete
 
Back
Top