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