準備ができたら C# コールバックを呼び出す F# 非同期計算を実行しようとしています。コードは次のとおりです。
type Worker() =
let locker = obj()
let computedValue = ref None
let started = ref false
let completed = Event<_>()
let doNothing() = ()
member x.Compute(callBack:Action<_>) =
let workAlreadyStarted, action =
lock locker (fun () ->
match !computedValue with
| Some value ->
true, (fun () -> callBack.Invoke value)
| None ->
completed.Publish.Add callBack.Invoke
if !started then
true, doNothing
else
started := true
false, doNothing)
action()
if not workAlreadyStartedthen
async {
// heavy computation to calc result
let result = "result"
lock locker (fun () ->
computedValue := Some result
completed.Trigger result)
} |> Async.Start
しかし、問題があります。完了したイベントをロックの外でトリガーしたいのですが、トリガーがスレッドセーフであることを確認したいです (実際、この小さな例では、他の誰も知らないので、ロックの外でイベントをトリガーするだけで済みます)購読しますが、常にそうであるとは限りません)。
C# イベントでは、これは非常に簡単に実現できます。
object locker = new object();
event Action<string> MyEvent;
void Raise()
{
Action<string> myEventCache;
lock (locker)
{
myEventCache = MyEvent;
}
if (myEventCache != null)
{
myEventCache("result");
}
}
ロック内でサブスクライバーのリストを凍結し、ロック外で呼び出して、F# イベントで同等のことを行うにはどうすればよいでしょうか?