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.