BeginInvoke without EndInvoke allowed?

  • Thread starter Thread starter Norman Diamond
  • Start date Start date
N

Norman Diamond

BeginInvoke returns an IAsyncResult, but in cases where the caller doesn't
care and couldn't do anything even if it did care, I don't assign the
returned value and assumed it would be garbage-collected.

Some bloggers say that this pattern leaks resources.

MSDN doesn't seem to see a problem with this pattern, so I wonder.

How to: Use a Background Thread to Search for Files
http://msdn2.microsoft.com/en-us/library/3s8xdz5c(VS.80).aspx
Example code has several calls to BeginInvoke and no calls to EndInvoke.
(Unlike my code this example uses the returned IAsyncResult, but this
example still doesn't call EndInvoke.)

Control.BeginInvoke Method (Delegate, Object[])
http://msdn2.microsoft.com/en-us/library/a06c0dc2(VS.80).aspx
Example code discards the returned IAsyncResult just like mine, and doesn't
call EndInvoke.

Of course in many situations it's not advisable to omit things like error
checking, but there's no point in my situation. The caller is a thread that
can't reasonably display UI. The target is a UI thread and it immediately
informs the user if it detects a problem.

So my concern is just whether this pattern is reliable or not. Will it leak
resources as some bloggers say? Or is it OK as MSDN seems to suggest?
 
Norman Diamond said:
BeginInvoke returns an IAsyncResult, but in cases where the caller doesn't
care and couldn't do anything even if it did care, I don't assign the
returned value and assumed it would be garbage-collected.

Some bloggers say that this pattern leaks resources.

In principle, it might at least *temporarily* leak resources. It
depends on the implementation. However, the Windows Forms team has
guaranteed that Control.BeginInvoke doesn't need a matching EndInvoke
call.

If you want "fire and forget" semantics you can use the class
implemented here:

http://www.yoda.arachsys.com/csharp/threads/threadpool.shtml
 
Jon Skeet said:
In principle, it might at least *temporarily* leak resources. It depends
on the implementation. However, the Windows Forms team has guaranteed that
Control.BeginInvoke doesn't need a matching EndInvoke call.

Thank you for responding, but I'm having trouble figuring out the answer(s).

In principle there might be resource leaks which might be at least
temporary, which means there's a chance the leaks might grow until the
process exits? So some bloggers are correct and MSDN (at least the two
pages which I cited last time) is wrong?

However, Control.BeginInvoke doesn't need a matching EndInvoke call for
which reason: because there is no leak, or because the leak is temporary
until garbage collection, or the leaks accumulate until the process exits
but luckily no one (including me so far) has been damaged by the leaks
accumulating too enormously?
If you want "fire and forget" semantics you can use the class implemented
here:
http://www.yoda.arachsys.com/csharp/threads/threadpool.shtml

Thank you. But I still don't understand: do I *need* the class that is
implemented there?

Again, in my situation I'm calling BeginInvoke on a private method in a
form, so the callee is running in the UI thread and if any errors occur
that's the time they're displayed. The caller is in a background thread
which is about to exit, it cannot do anything with a return value or any
other information, so "fire and forget" is suitable.
 
Norman said:
Thank you for responding, but I'm having trouble figuring out the answer(s).

In principle there might be resource leaks which might be at least
temporary, which means there's a chance the leaks might grow until the
process exits? So some bloggers are correct and MSDN (at least the two
pages which I cited last time) is wrong?

However, Control.BeginInvoke doesn't need a matching EndInvoke call for
which reason: because there is no leak, or because the leak is temporary
until garbage collection, or the leaks accumulate until the process exits
but luckily no one (including me so far) has been damaged by the leaks
accumulating too enormously?

Depending on the implementation of the IAsyncResult, a half-called async
method could leak synchronization primitives. They should be cleaned up
by the finalizer eventually, assuming that the finalizer thread isn't
blocked for some reason (some buggy finalizer somewhere). However,
synchronization primitives (usually) are OS resources and there are
performance concerns with keeping too many of them around. If you have a
server app which leaks them with abandon, far more of them will be alive
at any one time that necessary.

-- Barry
 
Norman Diamond said:
Thank you for responding, but I'm having trouble figuring out the answer(s).

In principle there might be resource leaks which might be at least
temporary, which means there's a chance the leaks might grow until the
process exits? So some bloggers are correct and MSDN (at least the two
pages which I cited last time) is wrong?

It's likely that finalizers will free up the resources, so they don't
leak as such (assuming things have been robustly implemented, of
course) - but the resources they temporarily hold might be required
*before* the finalizer is executed.
However, Control.BeginInvoke doesn't need a matching EndInvoke call for
which reason: because there is no leak, or because the leak is temporary
until garbage collection, or the leaks accumulate until the process exits
but luckily no one (including me so far) has been damaged by the leaks
accumulating too enormously?

BeginInvoke is implemented in Windows Forms has been implemented in
such a way that there's no leak, in my understanding.
Thank you. But I still don't understand: do I *need* the class that is
implemented there?

That depends on whether you're using Control.BeginInvoke or a delegate
BeginInvoke.
Again, in my situation I'm calling BeginInvoke on a private method in a
form, so the callee is running in the UI thread and if any errors occur
that's the time they're displayed. The caller is in a background thread
which is about to exit, it cannot do anything with a return value or any
other information, so "fire and forget" is suitable.

If you're using Control.BeginInvoke, you don't need to worry.
 
OK, I think this makes things clearer.

Calling BeginInvoke on an "ordinary" delegate, without calling EndInvoke,
can cause resource usages to hang around longer than necessary (until the
next garbage collection), which can cause temporary starvation in a server
or other victim when a heavy user of resources is present. However, there's
no permanent leak.

Calling BeginInvoke on Control, without calling EndInvoke, doesn't even have
that problem.

There are 8,192 executions of BeginInvoke in the situation I'm presently
concerned with, so I think that temporary starvation isn't happening, and
nothing worse can happen.

I still have some curiosity remaining from a former not-having-a-life as a
language lawyer. When I create a delegate that points to a private method
in a form, the form inherits from Control. But how is that enough to make
the delegate know whether to be a Control.something (with method
Control.BeginInvoke) or an "ordinary" delegate (with method
somethingelse.BeginInvoke)?
 
OK, I think this makes things clearer.

Good, my turn to confuse matters (i.e. create a mess that Jon has to clean
up :) ).
Calling BeginInvoke on an "ordinary" delegate, without calling
EndInvoke, can cause resource usages to hang around longer than
necessary (until the next garbage collection), which can cause temporary
starvation in a server or other victim when a heavy user of resources is
present. However, there's no permanent leak.

Calling BeginInvoke on Control, without calling EndInvoke, doesn't even
have that problem.

The first paragraph is correct for sure. I remain unconvinced that it's
untrue for Control.BeginInvoke(), at least as an unqualified statement.

Consider the statement in the doc page for IAsyncResult.AsyncWaitHandle:

Notes to Implementers The object that implements IAsyncResult
does not need to create the WaitHandle until the AsyncWaitHandle
property is read. It is the choice of the IAsyncResult
implementer. However, if the implementer creates AsyncWaitHandle,
it is the responsibility of the implementer to signal the
WaitHandle that will terminate the wait at the appropriate time.
For example, System.Runtime.Remoting.Messaging.AsyncResult
terminates the wait on behalf of the caller when an asynchronously
invoked method returns. Once created, AsyncWaitHandle should be
kept alive until the user calls the method that concludes the
asynchronous operation. At that time the object behind
AsyncWaitHandle can be discarded.

In other words, if the caller to Control.BeginInvoke() actually uses the
AsyncWaitHandle from the IAsyncResult it gets from Control.BeginInvoke(),
then that WaitHandle (which implements IDisposable and so must be disposed
when it's no longer needed) is required to be kept until the "_user_
[emphasis mine] calls the method that concludes the asynchronous
operation". In other words, the user's code has every reason to expect
that the WaitHandle will remain valid until that code calls
Control.EndInvoke().

So code that gets the AsyncWaitHandle is going to have to call EndInvoke()
to ensure they clean up that resource properly (EndInvoke() baing "the
method that concludes the asynchronous operation".

Beyond that, even if you can show in the current Control implementation
that there's no harm in not calling Control.EndInvoke(), I would say that
absent some clear, explicit statement in the MSDN documentation pages that
says that you don't need to call EndInvoke(), that pairing the two calls
may well be important, and very much _should_ be assumed to be so, at
least if your code uses the AsyncWaitHandle in the IAsyncResult, if not in
other cases.

I've looked for such a clear, explicit statement and haven't been able to
find one.

I'm carefully ignoring the fact that Control.BeginInvoke() doesn't follow
the normal pattern for async methods. There's no way to specify a
callback, never mind a context/state object for the callback. This means
it's practically impossible for the asynchronously invoked method to have
access to the IAsyncResult (it's not literally impossible, but it's
impractical because any attempt to provide access results in a race
condition...that can be addressed by adding thread synchronization, but
then that seems to me to negate the whole point of using BeginInvoke() in
the first place).

This means that if you _do_ call EndInvoke() you have to do it somewhere
other than the invoked delegate. This leads to inelegant things like
polling IAsyncResult.IsCompleted, or just calling EndInvoke() and possibly
getting blocked anyway. I suppose there are situations where this is
actually what you'd want to do, but being forced into seems kind of ugly
to me.

In other words, it bugs me that the whole Control.BeginInvoke() API is the
way it is. While I can understand the need for backward compatibility, I
don't understand why it remains in this sort of awkward state rather than
adding some overloads to Control.BeginInvoke() to allow it to be used in a
more typical fashion.
There are 8,192 executions of BeginInvoke in the situation I'm presently
concerned with, so I think that temporary starvation isn't happening,
and nothing worse can happen.

I suspect that as long as you do nothing with the IAsyncResult returned by
BeginInvoke(), you're fine. But I wish there was some more explicit
documentation to that effect.
I still have some curiosity remaining from a former not-having-a-life as
a language lawyer. When I create a delegate that points to a private
method in a form, the form inherits from Control. But how is that
enough to make the delegate know whether to be a Control.something (with
method Control.BeginInvoke) or an "ordinary" delegate (with method
somethingelse.BeginInvoke)?

One feature of delegates is that they are not specific to whatever method
they might be passed to. You can create a single delegate that is
suitable for either Control.BeginInvoke() or Delegate.BeginInvoke() (and
for the synchronous Invoke() equivalents as well). The delegate does not
need to be related to the Control class at all, never mind be an instance
member, or a member of any Control-derived class of any sort.

The corollary is that the delegate itself doesn't "know whether to be"
anything in particular, nor does it need to. The sole determining factor
is how you use it If you call Control.BeginInvoke(), then it's used by
Control.BeginInvoke(), executed on that Control instance's owning thread.
If you call Delegate.BeginInvoke() on the delegate instance itself, then
it's invoked asynchronously via that method.

Pete
 
even if you can show in the current Control implementation that there's no
harm in not calling Control.EndInvoke(), I would say that absent some
clear, explicit statement in the MSDN documentation pages that says that
you don't need to call EndInvoke(), that pairing the two calls may well be
important, and very much _should_ be assumed to be so,

Yeah, present some clear, explicit examples isn't enough. And with our
knowledge of MSDN, even present some clear, explicit statement might not be
enough either.

EndInvoke would impose an unnecessary delay on the background thread where I
call BeginInvoke. The more I think about it, there's a tiny chance that I
have a race condition now, and if I do then it might be minimizable by
making the UI thread sleep a few milliseconds. If the background thread
gets delayed and causes a race condition then there's no solution at all.
EndInvoke would only magnify it.
One feature of delegates is that they are not specific to whatever method
they might be passed to. You can create a single delegate that is
suitable for either Control.BeginInvoke() or Delegate.BeginInvoke() (and
for the synchronous Invoke() equivalents as well).

My copy of MSDN doesn't have Delegate.BeginInvoke. It has
Delegate.DynamicInvoke. I thought C#'s delegate.Invoke and
delegate.BeginInvoke were fictions invented by the C# compiler, calling some
..Net stuff which I haven't quite figured out yet.
If you call Control.BeginInvoke(), then it's used by
Control.BeginInvoke(), executed on that Control instance's owning thread.
If you call Delegate.BeginInvoke() on the delegate instance itself, then
it's invoked asynchronously via that method.

Since I'm a Form and I call this.BeginInvoke on the delegate, I'm safely
calling Control.BeginInvoke, right?

Ugh, that needs clarification. I'm a Form, but one of my methods can be
called by a background thread. This is where I have to BeginInvoke my own
other method that operates on me, and return immediately to the background
thread who called me.


Peter Duniho said:
OK, I think this makes things clearer.

Good, my turn to confuse matters (i.e. create a mess that Jon has to clean
up :) ).
Calling BeginInvoke on an "ordinary" delegate, without calling
EndInvoke, can cause resource usages to hang around longer than
necessary (until the next garbage collection), which can cause temporary
starvation in a server or other victim when a heavy user of resources is
present. However, there's no permanent leak.

Calling BeginInvoke on Control, without calling EndInvoke, doesn't even
have that problem.

The first paragraph is correct for sure. I remain unconvinced that it's
untrue for Control.BeginInvoke(), at least as an unqualified statement.

Consider the statement in the doc page for IAsyncResult.AsyncWaitHandle:

Notes to Implementers The object that implements IAsyncResult
does not need to create the WaitHandle until the AsyncWaitHandle
property is read. It is the choice of the IAsyncResult
implementer. However, if the implementer creates AsyncWaitHandle,
it is the responsibility of the implementer to signal the
WaitHandle that will terminate the wait at the appropriate time.
For example, System.Runtime.Remoting.Messaging.AsyncResult
terminates the wait on behalf of the caller when an asynchronously
invoked method returns. Once created, AsyncWaitHandle should be
kept alive until the user calls the method that concludes the
asynchronous operation. At that time the object behind
AsyncWaitHandle can be discarded.

In other words, if the caller to Control.BeginInvoke() actually uses the
AsyncWaitHandle from the IAsyncResult it gets from Control.BeginInvoke(),
then that WaitHandle (which implements IDisposable and so must be disposed
when it's no longer needed) is required to be kept until the "_user_
[emphasis mine] calls the method that concludes the asynchronous
operation". In other words, the user's code has every reason to expect
that the WaitHandle will remain valid until that code calls
Control.EndInvoke().

So code that gets the AsyncWaitHandle is going to have to call EndInvoke()
to ensure they clean up that resource properly (EndInvoke() baing "the
method that concludes the asynchronous operation".

Beyond that, even if you can show in the current Control implementation
that there's no harm in not calling Control.EndInvoke(), I would say that
absent some clear, explicit statement in the MSDN documentation pages that
says that you don't need to call EndInvoke(), that pairing the two calls
may well be important, and very much _should_ be assumed to be so, at
least if your code uses the AsyncWaitHandle in the IAsyncResult, if not in
other cases.

I've looked for such a clear, explicit statement and haven't been able to
find one.

I'm carefully ignoring the fact that Control.BeginInvoke() doesn't follow
the normal pattern for async methods. There's no way to specify a
callback, never mind a context/state object for the callback. This means
it's practically impossible for the asynchronously invoked method to have
access to the IAsyncResult (it's not literally impossible, but it's
impractical because any attempt to provide access results in a race
condition...that can be addressed by adding thread synchronization, but
then that seems to me to negate the whole point of using BeginInvoke() in
the first place).

This means that if you _do_ call EndInvoke() you have to do it somewhere
other than the invoked delegate. This leads to inelegant things like
polling IAsyncResult.IsCompleted, or just calling EndInvoke() and possibly
getting blocked anyway. I suppose there are situations where this is
actually what you'd want to do, but being forced into seems kind of ugly
to me.

In other words, it bugs me that the whole Control.BeginInvoke() API is the
way it is. While I can understand the need for backward compatibility, I
don't understand why it remains in this sort of awkward state rather than
adding some overloads to Control.BeginInvoke() to allow it to be used in a
more typical fashion.
There are 8,192 executions of BeginInvoke in the situation I'm presently
concerned with, so I think that temporary starvation isn't happening,
and nothing worse can happen.

I suspect that as long as you do nothing with the IAsyncResult returned by
BeginInvoke(), you're fine. But I wish there was some more explicit
documentation to that effect.
I still have some curiosity remaining from a former not-having-a-life as
a language lawyer. When I create a delegate that points to a private
method in a form, the form inherits from Control. But how is that
enough to make the delegate know whether to be a Control.something (with
method Control.BeginInvoke) or an "ordinary" delegate (with method
somethingelse.BeginInvoke)?

One feature of delegates is that they are not specific to whatever method
they might be passed to. You can create a single delegate that is
suitable for either Control.BeginInvoke() or Delegate.BeginInvoke() (and
for the synchronous Invoke() equivalents as well). The delegate does not
need to be related to the Control class at all, never mind be an instance
member, or a member of any Control-derived class of any sort.

The corollary is that the delegate itself doesn't "know whether to be"
anything in particular, nor does it need to. The sole determining factor
is how you use it If you call Control.BeginInvoke(), then it's used by
Control.BeginInvoke(), executed on that Control instance's owning thread.
If you call Delegate.BeginInvoke() on the delegate instance itself, then
it's invoked asynchronously via that method.

Pete
 
Yeah, present some clear, explicit examples isn't enough. And with our
knowledge of MSDN, even present some clear, explicit statement might not
be enough either.

While I like good sample code, it's no substitute for actual
documentation. If nothing else, I have seen MSDN code samples that I know
for a fact are wrong. Documenting by example doesn't work very well,
regardless.
EndInvoke would impose an unnecessary delay on the background thread
where I call BeginInvoke. The more I think about it, there's a tiny
chance that I have a race condition now, and if I do then it might be
minimizable by making the UI thread sleep a few milliseconds. If the
background thread gets delayed and causes a race condition then there's
no solution at all. EndInvoke would only magnify it.

For what it's worth, calling sleep is not a good way to address a race
condition. It may reduce the chances of a problem, but it's not a good
way to eliminate the chances. You either need to synchronize your
threads, or just allow the race to occur and handle it gracefully.
My copy of MSDN doesn't have Delegate.BeginInvoke. It has
Delegate.DynamicInvoke. I thought C#'s delegate.Invoke and
delegate.BeginInvoke were fictions invented by the C# compiler, calling
some .Net stuff which I haven't quite figured out yet.

They are created by the compiler, but they aren't fictions. Not as far as
I know, anyway. My understanding is that they are considered part of the
Delegate class, even though they are compiler-dependent. Anyway, writing
"Delegate.BeginInvoke()" seems easier to me that some alternative
description, even if technically the method's not part of the class. :)
Since I'm a Form and I call this.BeginInvoke on the delegate, I'm safely
calling Control.BeginInvoke, right?

Ugh, that needs clarification. I'm a Form, but one of my methods can be
called by a background thread. This is where I have to BeginInvoke my
own other method that operates on me, and return immediately to the
background thread who called me.

If the code calling Control.BeginInvoke() is an instance member of a
Control-derived class, then yes...if you call "this.BeginInvoke()" you are
definitely calling Control.BeginInvoke(). Of course, you don't actually
need the "this." part.

Since Form inherits Control, any Form-derived class you write will behave
like this. This is basic C#/OOP behavior...don't let the fact that you're
dealing with this funny BeginInvoke() pattern make you think that it
doesn't otherwise work like any other call. The funny business happens in
the parameters for the method, not the call to the method itself. :)

Pete
 
Norman said:
My copy of MSDN doesn't have Delegate.BeginInvoke. It has
Delegate.DynamicInvoke. I thought C#'s delegate.Invoke and
delegate.BeginInvoke were fictions invented by the C# compiler, calling some
.Net stuff which I haven't quite figured out yet.

The declaration of the Invoke, BeginInvoke and EndInvoke methods are
dependent on the type of the delegate. Calling Invoke directly is
identical to calling the delegate; when the compiler sees you calling a
delegate, it actually inserts a call to the Invoke method.

The BeginInvoke/EndInvoke methods are similarly magic. Their
implementations are provided by the CLR.

-- Barry
 
Back
Top