この質問に対する Andreas Huber の回答Concurrent<T>
により、ThreadPool の代わりに非同期デリゲートを使用して実装するというアイデアが得られました。AsyncCallback
ただし、が に渡されたときに何が起こっているのかを理解するのが難しくなっています。BeginInvoke
特に、複数のスレッドが にアクセスしている場合はそうIAsyncResult
です。残念ながら、このケースは MSDN や私が見つけたどこでもカバーされていないようです。さらに、私が見つけたすべての記事は、クロージャーとジェネリックが利用可能になる前に書かれたか、単にそのように見えます。いくつかの質問があります (答えが正しいことを願っていますが、がっかりすることは覚悟しています):
1) クロージャを AsyncCallback として使用すると違いはありますか?
(うまくいかないことを願っています)
2) スレッドが で待機している場合、
a) コールバックが開始する前、または b) 終了後にAsyncWaitHandle
通知されますか?
(できれば b)
3) コールバックが実行されている間、何が返されますか? 私が見ることができる可能
性: b) ; c)コールバックが EndInvoke を呼び出す前、後。
(願わくば b または c)
4)呼び出された後にスレッドが待機すると、スローされますか?
(そうではないことを願っていますが、私はそう期待しています)。IsCompleted
true
false
false
true
DisposedObjectException
AsyncWaitHandle
EndInvoke
答えが私が望んでいるものであれば、これはうまくいくようです:
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
}
...
質問 1 から 3 への回答が私が望んでいるものである場合、私が見る限り、ここにレース条件はないはずです。