An Mvar
is a mutable location that is either empty or contains a value. One can
put
or set
the value, and wait on value_available
for the location to be filled
in either way.
Having an Mvar.Writer.t
gives the capability to mutate the mvar.
The key difference between an Mvar
and an Ivar
is that an Mvar
may be filled
multiple times.
This implementation of Mvar
also allows one to replace the value without any
guarantee that the reading side has seen it. This is useful in situations where
last-value semantics are desired (i.e. you want to signal whenever a config file is
updated, but only care about the most recent values).
A Mvar
can also be used as a baton passing mechanism between a producer
and consumer. For instance, a producer reading from a socket and producing
a set of deserialized messages can put the batch from a single read into an
Mvar
and can wait for taken
to return as a pushback mechanism. The
consumer meanwhile waits on value_available
. This way the natural batch
size is passed between the two sub-systems with minimal overhead.
include sig ... end
val sexp_of_t : ('a ‑> Sexplib.Sexp.t) ‑> ('phantom ‑> Sexplib.Sexp.t) ‑> ('a, 'phantom) t ‑> Sexplib.Sexp.t
module Read_write : sig ... end
module Read_only : sig ... end
val create : unit ‑> 'a Read_write.t
val is_empty : (_, _) t ‑> bool
val put : ('a, [> Core_kernel.write ]) t ‑> 'a ‑> unit Async_kernel.Deferred.t
put t a
waits until is_empty t
, and then does set t a
. If there are multiple
concurrent put
s, there is no fairness guarantee (i.e. put
s may happen out of order
or may be starved).
val set : ('a, [> Core_kernel.write ]) t ‑> 'a ‑> unit
set t a
sets the value in t
to a
, even if not (is_empty t)
. This is useful if
you want takers to have last-value semantics.
val update : ('a, Core_kernel.read_write) t ‑> f:('a option ‑> 'a) ‑> unit
update t ~f
applies f
to the value in t
and set
s t
to the result. This is
useful if you want takers to have accumulated-value semantics. update_exn
is like
update
, except it raises if is_empty t
.
val update_exn : ('a, Core_kernel.read_write) t ‑> f:('a ‑> 'a) ‑> unit
val read_only : ('a, [> Core_kernel.read ]) t ‑> ('a, Core_kernel.read) t
val write_only : ('a, [> Core_kernel.write ]) t ‑> ('a, Core_kernel.write) t
val value_available : (_, [> Core_kernel.read ]) t ‑> unit Async_kernel.Deferred.t
value_available t
returns a deferred d
that becomes determined when a value is in
t
. d
does not include the value in t
because that value may change after d
becomes determined and before a deferred bind on d
gets to run.
Repeated calls to value_available t
will always return the same deferred until
the t
is filled.
val take : ('a, [> Core_kernel.read ]) t ‑> 'a Async_kernel.Deferred.t
take t
returns a deferred that, when t
is filled, becomes determined with the
value of t
and and clears t
. If there are multiple concurrent calls to take
then only one of them will be fulfilled and the others will continue waiting on future
values. There is no ordering guarantee for which take
call will be filled first.
val take_now_exn : ('a, [> Core_kernel.read ]) t ‑> 'a
val taken : (_, [> Core_kernel.write ]) t ‑> unit Async_kernel.Deferred.t
taken t
returns a deferred that is filled the next time take
clears t
.
val peek : ('a, [> Core_kernel.read ]) t ‑> 'a option
peek t
returns the value in t
without clearing t
, or returns None
is is_empty
t
. peek_exn t
is like peek
, except it raises if is_empty t
.
val peek_exn : ('a, [> Core_kernel.read ]) t ‑> 'a