Parallel_capsule.With_mutexSourceval with_lock :
'a ('b : value_or_null). Parallel_kernel.t @ local ->
'a t ->
f:
(Parallel_kernel.t @ local -> ('a -> 'b @ portable contended) @ local once) @ local once portable unyielding ->
'b @ portable contendedwith_lock parallel t ~f locks the mutex associated with t and calls f on the protected value with access to parallel for doing parallel work, returning the result.
val with_lock_or_cancel :
'a ('b : value_or_null). Parallel_kernel.t @ local ->
Await.Cancellation.t @ local ->
'a t ->
f:
(Parallel_kernel.t @ local -> ('a -> 'b @ portable contended) @ local once) @ local once portable unyielding ->
'b Await.Or_canceled.t @ portable contendedwith_lock_or_cancel parallel c t ~f is Completed (with_lock parallel t ~f) if c is not canceled, otherwise it is Canceled.
val with_scoped :
'a ('b : value_or_null). Parallel_kernel.t @ local ->
'a t ->
f:
(Parallel_kernel.t @ local ->
('a Await.Capsule.Scoped.t @ local ->
'b) @ local once) @ local once unyielding ->
'bwith_scoped parallel t ~f locks the mutex associated with t and calls f with parallel and a Scoped.t for the protected data, returning the result.
Since the provided callback does not have to be portable, this is useful when you need to acquire two mutexes for different capsules at the same time and move data between them. For example:
open! Core
open! Await
(* Lock both mutexes, and set the value of both refs to the maximum of their
previous values, without any data races
Make sure to always call this with locks in the same order, to avoid deadlocks! *)
let set_to_max
: Parallel.t @ local -> int ref Capsule.Sync.With_mutex.t
-> int ref Capsule.Sync.With_mutex.t -> unit
=
fun par ref1 ref2 ->
Parallel.Capsule.With_mutex.with_scoped par ref1 ~f:(fun par scope1 ->
Parallel.Capsule.With_mutex.with_scoped par ref2 ~f:(fun _par scope2 ->
(* At this point we have both mutexes locked, so we can freely manipulate
the data they protect without the potential for data races *)
let value1 = Capsule.Scoped.get scope1 ~f:(fun r -> !r) in
let value2 = Capsule.Scoped.get scope2 ~f:(fun r -> !r) in
let new_value = Int.max value1 value2 in
Capsule.Scoped.iter scope1 ~f:(fun r -> r := new_value);
Capsule.Scoped.iter scope2 ~f:(fun r -> r := new_value) [@nontail])
[@nontail])
[@nontail]
;;val with_scoped_or_cancel :
'a ('b : value_or_null). Parallel_kernel.t @ local ->
Await.Cancellation.t @ local ->
'a t ->
f:
(Parallel_kernel.t @ local ->
('a Await.Capsule.Scoped.t @ local ->
'b) @ local once) @ local once unyielding ->
'b Await.Or_canceled.twith_scoped_or_cancel parallel c t ~f is Completed (with_scoped parallel t ~f) if c is not canceled, otherwise it is Canceled.