我在思考线程安全的懒惰,即在强制时,我们需要确保进程是线程安全的。
这是我写的代码:
type 'a t =
| Delayed of (unit -> 'a)
| Value of 'a
| Exn of exn
type 'a lazy_t = Mutex.t * ('a t ref)
let lazy_of_value x = Mutex.create(), ref (Value x)
let lazy_of_fun f = Mutex.create(), ref (Delayed f)
let force (m, t) =
Mutex.lock m;
let x =
match !t with
| Value v -> v
| Exn e -> Mutex.unlock m; raise e
| Delayed f ->
try
let v = f () in
t := Value v;
v
with e -> t := Exn e; Mutex.unlock m; raise e
in
Mutex.unlock m;
x
基本上,我将一个懒惰类型的锁附加为一个新的懒惰类型。
我将整个力量过程包裹在锁定/解锁中,但我做的是正确的吗?
或者我只需要在处理Delayed
我有这个问题,因为我认为force
只会在处理Delayed
时写入/修改懒惰一次,但一旦确定就可能有很多读取。因此,如果我将整个过程包装起来,它肯定是线程安全的,但是对于常量锁定解锁会有糟糕的性能。我是对的吗?
答案 0 :(得分:1)
正如评论中暗示的那样,你可以在延迟函数的评估中使用第二层懒惰:
type 'a t =
| Delayed of (unit -> 'a)
| Value of 'a
| Exn of exn
type 'a lazy_t = 'a t ref
let lazy_of_value x = ref (Value x)
let lazy_of_fun f =
let m = Mutex.create () in
let v = lazy (f ()) in
let rec r = ref (Delayed (fun () ->
Mutex.lock m;
try
let v = Lazy.force v in
r := Value v;
Mutex.unlock m;
v
with e -> r := Exn e; Mutex.unlock m; raise e
))
in r
let force t =
let x =
match !t with
| Value v -> v
| Exn e -> raise e
| Delayed f -> f ()
in
x
请注意,互斥锁已从外部ref
值中完全消除。
来自你的评论:
如果有人想在
f()
进行阅读时会怎样?
两种可能性:
外部参考已经更新,新人只看到Value
,所以没问题。
外部引用仍然是Delayed
,这意味着新线程将尝试执行f
。如果另一个帖子在Delayed
已经被执行时想要lock
,它将在lazy
停止,并且当它继续时,内部Value
将被强制执行。另一方面,如果在更新外部引用之后出现一个线程,它只会看到ref
,因此不必通过互斥锁定机制 。我可以预见的唯一可能的问题是,如果使用Value v
1 对外ref
进行第二次分配,实际上会导致在{{1}中设置不同的物理值因此,打破任何可能的进一步物理比较,但我不认为它可能会发生(我们需要一个大师来确认)。
编辑:
这是一个不使用Lazy.t
的实现。
type 'a t =
| Delayed of (unit -> 'a)
| Value of 'a
| Exn of exn
type 'a lazy_t = 'a t ref
type 'a inner = 'a t ref
let lazy_of_value x = ref (Value x)
let lazy_of_fun f =
let m = Mutex.create () in
let v = ref (Delayed f) in
let rec r = ref (Delayed (fun () ->
Mutex.lock m;
try
let v' =
match !v with
(* first evaluation *)
| Delayed f ->f ()
(* other concurrent evaluations *)
| Value v -> v
| Exn e -> raise e
in
v := Value v';
r := Value v';
Mutex.unlock m;
v'
with e -> r := Exn e; Mutex.unlock m; raise e
))
in r
let force t =
let x =
match !t with
| Value v -> v
| Exn e -> raise e
| Delayed f -> f ()
in
x
警告:两个未经测试的代码。
(1):如果至少有两个线程同时运行延迟函数,则会发生这种情况。