3
我試圖做一個F#異步計算,在準備好時調用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#事件的等效,凍結鎖內的用戶的列表中,但調用它鎖外面?
您確定C#凍結了用戶列表嗎?你不是在參考這個活動嗎? – Daniel 2013-02-25 15:04:31
無論何時向事件添加新的處理程序,都會創建一個新的委託值並替換以前的值,因此,如果在複製代理的值時添加了另一個處理程序,則它將不會鏈接到製作的副本 – 2013-02-25 15:09:31
如果您需要訪問訂閱者列表,那麼您可以使用自己的'IEvent <_>'實現,而不是使用'Event <_> .Publish'提供的實現。 – kvb 2013-02-25 19:57:46