BeginInvoke / EndInvoke race condition

  • Thread starter Thread starter stork
  • Start date Start date
S

stork

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!
 
stork said:
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).
 
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?
 
stork said:
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.
 
Back
Top