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