In asynchronous model, IAsyncResult.AsyncWaitHandle signaled first, or AsyncCallback invoked first?

  • Thread starter Thread starter Morgan Cheng
  • Start date Start date
M

Morgan Cheng

In asynchronous model, BeginXXX method returns a IAsnycResult-derived
object. IAsyncResult.AsyncWaitHandle will be signaled when the
asynchronous job is complete; and BeginXXX method has a argument as
AsyncCallback to be invoked when the job is complete.

I am wondering. When the asynchronous is complete, is
IAsyncResult.AsyncWaitHandle be signaled first, or AsyncCallback be
invoked first?
 
Morgan said:
[...]
I am wondering. When the asynchronous is complete, is
IAsyncResult.AsyncWaitHandle be signaled first, or AsyncCallback be
invoked first?

Surely they are effectively simultaneous. That is, obviously one
happens before the other. But they likely occur in practically
immediate sequence, and because of the way thread scheduling works on
Windows, it's entirely possible that if you have both a callback and a
thread waiting on the WaitHandle, that either the code in the callback
or the code waiting on the WaitHandle could get scheduled next.

In other words, even if one or the other is technically always done
first, the observed result could in fact be the opposite. I would
suggest that this is one of those things that you should not assume is
well-defined and should not rely on a specific behavior in code,
especially if you are asking as a general question related to anything
that uses IAsyncResult (even if the behavior is well-defined for a
particular class, I'm not sure you could depend on it being well-defined
for _all_ classes that implement the asynchronous paradigm).

I'm curious if there's a specific scenario in which this question came
up? It seems like an interesting enough academic question, but since
you would normally use _either_ the WaitHandle _or_ a callback, not both
together, it's not clear why this would come up in actual code.

Pete
 
Morgan said:
[...]
I am wondering. When the asynchronous is complete, is
IAsyncResult.AsyncWaitHandle be signaled first, or AsyncCallback be
invoked first?

Surely they are effectively simultaneous. That is, obviously one
happens before the other. But they likely occur in practically
immediate sequence, and because of the way thread scheduling works on
Windows, it's entirely possible that if you have both a callback and a
thread waiting on the WaitHandle, that either the code in the callback
or the code waiting on the WaitHandle could get scheduled next.

In other words, even if one or the other is technically always done
first, the observed result could in fact be the opposite. I would
suggest that this is one of those things that you should not assume is
well-defined and should not rely on a specific behavior in code,
especially if you are asking as a general question related to anything
that uses IAsyncResult (even if the behavior is well-defined for a
particular class, I'm not sure you could depend on it being well-defined
for _all_ classes that implement the asynchronous paradigm).

I'm curious if there's a specific scenario in which this question came
up? It seems like an interesting enough academic question, but since
you would normally use _either_ the WaitHandle _or_ a callback, not both
together, it's not clear why this would come up in actual code.

Pete


I did some googling and find this post
http://www.bluebytesoftware.com/blog/2006/06/12/ImplementingAHighperfIAsyncResultAddendum.aspx.
The correct sequence should be
1) set IsCompleted to true,
2) signal the handle,
3) invoke the callback.

This is reasonable, because the callback function might wait on the
AsyncWaitHandle. If the sequence of 2) & 3) is inverted, it would be a
deadlock.
Even the callback doesn't depends on the AsyncWaitHandle, it might be
a time-costing operation, which can delay signaling of
AsyncWaitHandle. And, if other operations depends on AsyncWaitHandle,
they are delayed. That's not good.

With the help of Lutz Roeder's .Net Reflector, I read the reflected
code of System.Web.Services.Protocols.WebClientAsyncResult, which is a
subclass of IAsyncResult. Its Complete function does in the sequence
as mentioned above.

Of course the implementation can be like this
1) set IsCompleted to true;
2) invoke the callback with BeginInvoke;
3) signal the handle
But this involves a unnecessary threading switch.
 
Morgan said:
I did some googling and find this post
http://www.bluebytesoftware.com/blog/2006/06/12/ImplementingAHighperfIAsyncResultAddendum.aspx.
The correct sequence should be
1) set IsCompleted to true,
2) signal the handle,
3) invoke the callback.

This is reasonable, because the callback function might wait on the
AsyncWaitHandle. If the sequence of 2) & 3) is inverted, it would be a
deadlock.

Only if the same thread that is processing the signaling is used to run
the callback. AFAIK, there's no requirement that that's how the async
paradigm is implemented. A class implementing the async paradigm could,
for example, simply use Delegate.BeginInvoke() to execute the callback.

You mention this at the end of your post, but with the implication that
because of the extra thread, that technique wouldn't be used. While it
may be true that no implementation of the async paradigm uses
Delegate.BeginInvoke(), IMHO the extra thread doesn't prove that to be
the case. It's not uncommon at all to make a trade-off for code
robustness over performance.
Even the callback doesn't depends on the AsyncWaitHandle, it might be
a time-costing operation, which can delay signaling of
AsyncWaitHandle. And, if other operations depends on AsyncWaitHandle,
they are delayed. That's not good.

See above.
With the help of Lutz Roeder's .Net Reflector, I read the reflected
code of System.Web.Services.Protocols.WebClientAsyncResult, which is a
subclass of IAsyncResult. Its Complete function does in the sequence
as mentioned above.

So, you have found a single example of that implementation. That
doesn't tell you whether that's the standard way of implementation.

But let's assume it is. You still cannot rely on this information in
any useful way. In fact, this is especially true if the thread setting
the handle is the same one on which the callback is executed. Just
because the WaitHandle gets set, that doesn't mean that the thread
waiting on it will run immediately. It just puts that thread into a
runnable state.

So, the thread setting the WaitHandle then goes off an executes the
callback. Until that thread exhausts its quantum or hits some sort of
wait state itself, the thread waiting on the WaitHandle still isn't
going to execute.

So even though the WaitHandle is set before the callback is executed,
the _observed_ effect is that the callback is executed _before_ the
thread waiting on the WaitHandle.

And you can't even rely on it always getting reversed like this. The
order of execution of a thread waiting on the WaitHandle and the
callback depends on both the exact implementation of the class
implementing the async paradigm, _and_ on the exact timing and sequence
of various threads executing or waiting.

So, I refer you back to my previous comment/question:

I'm curious if there's a specific scenario in which
this question came up? It seems like an interesting
enough academic question, but since you would
normally use _either_ the WaitHandle _or_ a callback,
not both together, it's not clear why this would come
up in actual code.

Even if there's a reliable answer to the question you asked (and I'm not
convinced there is), it doesn't seem like this is the sort of thing
you'd need to know while coding an actual application.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top