Andreas Huber's answer to this question gave me an idea to implement Concurrent<T>
with async delegates instead of the ThreadPool. However, I am finding it harder to understand what's going on when an AsyncCallback
is passed to BeginInvoke
, especially when several threads have access to IAsyncResult
. Unfortunately, this case doesn't seem to be covered at MSDN or anywhere I could find. Moreover, all articles I could find were either written before closures and generics were available or just seem that way. There are several questions (and the answers which I hope are true, but I am ready to be disappointed):
1) Would using a closure as an AsyncCallback make any difference?
(Hopefully not)
2) If a thread waits on the AsyncWaitHandle
, will it be signaled
a) before the callback starts or
b) after it finishes?
(Hopefully b)
3) While the callback is running, what will IsCompleted
return? Possibilities I can see:
a) true
;
b) false
;
c) false
before the callback calls EndInvoke, true
after.
(Hopefully b or c)
4) Will DisposedObjectException
be thrown if some thread waits on the AsyncWaitHandle
after EndInvoke
is called?
(Hopefully not, but I expect yes).
Provided the answers are as I hope, this seems like it should work:
public class Concurrent<T> {
private IAsyncResult _asyncResult;
private T _result;
public Concurrent(Func<T> f) { // Assume f doesn't throw exceptions
_asyncResult = f.BeginInvoke(
asyncResult => {
// Assume assignment of T is atomic
_result = f.EndInvoke(asyncResult);
}, null);
}
public T Result {
get {
if (!_asyncResult.IsCompleted)
// Is there a race condition here?
_asyncResult.AsyncWaitHandle.WaitOne();
return _result; // Assume reading of T is atomic
}
...
If the answers to the questions 1-3 are the ones I hope for, there should be no raace condition here, as far as I can see.