簡體   English   中英

線程安全地提升F#事件

[英]Thread-safe raising of F# events

我正在嘗試進行F#異步計算,在准備就緒時調用C#回調。 代碼如下:

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#事件執行等效操作,凍結鎖內的訂戶列表,但在鎖外調用它?

這在F#中並不那么簡單,因為Event<_>不公開其訂閱者列表,該列表由Add / Remove突變。

您可以通過為每個處理程序創建新事件來避免此突變。

let mutable completed = Event<_>()

//...

let ev = Event<_>()
let iev = ev.Publish
iev.Add(completed.Trigger)
iev.Add(callBack.Invoke)
completed <- ev

//...

let ev = lock locker <| fun () -> 
    computedValue := Some result
    completed
ev.Trigger(result)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM