Because the results to BeginInvoke occur async'ly, it stands to reason
that each call of execute is actually a record on a queue, and
therefor, each asyncResult must actually be a separate item on that
queue. Conceptually, the nicest place to put the IAsyncResult to use
for EndInvoke is with the queued item itself, that is, in the execute
method that BeginInvoke enqueued. BeginInvoke fires as needed, and the
"invoked" method cleans itself up by calling the matching EndInvoke.

But, there's no way to actually make this work as above. BeginInvoke
can hit execute before any possible asyncResult assignment takes place.
Consider this pseudocode example:

class MyForm{ }

class MyWorkerThread
{
MyForm form;
IAsyncResult asyncResult;

void execute()
{
form.EndInvoke( asyncResult );
}

void start(int 42)
{
asyncResult = form.BeginInvoke( new executeDelegate( execute ) );
}
}

In the above, asyncResult will be null or invalid inside of execute()
because the assignment to asyncResult will not be completed yet until
the execute() is reached. Short of locking, is there another way to
call form.BeginInvoke so that the asyncResult is passed with it?
Thanks!

Re: BeginInvoke / EndInvoke race condition by Jon

Jon
Wed Jan 26 01:12:52 CST 2005

stork <tbandrow@mightyware.com> wrote:
> Because the results to BeginInvoke occur async'ly, it stands to reason
> that each call of execute is actually a record on a queue, and
> therefor, each asyncResult must actually be a separate item on that
> queue. Conceptually, the nicest place to put the IAsyncResult to use
> for EndInvoke is with the queued item itself, that is, in the execute
> method that BeginInvoke enqueued. BeginInvoke fires as needed, and the
> "invoked" method cleans itself up by calling the matching EndInvoke.
>
> But, there's no way to actually make this work as above. BeginInvoke
> can hit execute before any possible asyncResult assignment takes place.
> Consider this pseudocode example:
>
> class MyForm{ }
>
> class MyWorkerThread
> {
> MyForm form;
> IAsyncResult asyncResult;
>
> void execute()
> {
> form.EndInvoke( asyncResult );
> }
>
> void start(int 42)
> {
> asyncResult = form.BeginInvoke( new executeDelegate( execute ) );
> }
> }
>
> In the above, asyncResult will be null or invalid inside of execute()
> because the assignment to asyncResult will not be completed yet until
> the execute() is reached. Short of locking, is there another way to
> call form.BeginInvoke so that the asyncResult is passed with it?

I can't immediately see one, no. Do you definitely *need* to call
EndInvoke in your real code? There's no requirement for it from the
framework's point of view (unlike with other, similar EndXXX methods).

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Re: BeginInvoke / EndInvoke race condition by stork

stork
Wed Jan 26 08:50:23 CST 2005

TJB replied to:

> I can't immediately see one, no. Do you definitely *need* to call
> EndInvoke in your real code? There's no requirement for it from the
> framework's point of view (unlike with other, similar EndXXX
methods).

I thought that EndInvoke did some sort of cleanup. I'm reading
Control.*Invoke as being a different PostMessage based animal than the
normal asynch delegates *Invoke, which use the worker thread pool. So
are you saying that it is not necessary to call Control.EndInvoke?


Re: BeginInvoke / EndInvoke race condition by Jon

Jon
Wed Jan 26 11:20:56 CST 2005

stork <tbandrow@mightyware.com> wrote:
> > I can't immediately see one, no. Do you definitely *need* to call
> > EndInvoke in your real code? There's no requirement for it from the
> > framework's point of view (unlike with other, similar EndXXX
> methods).
>
> I thought that EndInvoke did some sort of cleanup. I'm reading
> Control.*Invoke as being a different PostMessage based animal than the
> normal asynch delegates *Invoke, which use the worker thread pool. So
> are you saying that it is not necessary to call Control.EndInvoke?

Exactly. Note that this doesn't apply to other things (BeginRead,
Delegate.BeginInvoke etc) - it *only* applies to Control.BeginInvoke.

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too