Module Portable_kernel.Atomic

An atomic (mutable) reference to a value of type 'a.

Atomic references mode cross both contention and portability, meaning they are always uncontended and always portable, regardless of the kind of the 'a type parameter, or the mode of the atomic reference itself.

For atomic integers, always mutate their value using one of the intrinsic operations (fetch_and_add, add, sub, logand, logor, logxor, incr, or decr). For atomic references to complex structures, use update to atomically update the atomic. For example, to atomically add a value to a Set:

  open! Base
  open! Portable

  let atomically_add_to_set (set_atomic : Set.M(Int).t Atomic.t) value =
    Atomic.update set_atomic ~pure_f:(fun set -> Set.add set value)
  ;;
module Compare_failed_or_set_here : sig ... end
type !('a : value_or_null) t = 'a Basement.Portable_atomic.t
include sig ... end
val sexp_of_t : 'a. ('a -> Sexplib0.Sexp.t) -> 'a t -> Sexplib0.Sexp.t
include sig ... end
val t_of_sexp : 'a. (Sexplib0.Sexp.t -> 'a) -> Sexplib0.Sexp.t -> 'a t
val make : 'a. ?padded:bool @ local -> ('a @ portable contended -> 'a t) @ local @@ portable

make v creates an atomic reference with initial value v.

The optional padded argument specifies whether or not the atomic reference should be padded to cache line size to avoid false sharing. When padded, i.e. ~padded:true, an atomic reference occupies 4-16x the memory of one allocated without padding. By default padded is false.

When a CPU core attempts to perform a write, it takes exclusive ownership of the entire cache line containing the memory location being written to. This means that accessing disjoint memory locations sharing a cache line when at least one of those accesses is a write is impossible. This is called false sharing. The cache coherence traffic due to repeated invalidations can quickly become very expensive.

As a general guideline, it is typically beneficial to pad data structures that live for a long time and are frequently accessed by multiple CPU cores and frequently written to by at least one CPU core.

val get : 'a. 'a t -> 'a @ portable contended @@ portable

get r gets the the current value of r.

val set : 'a. 'a t -> 'a @ portable contended -> unit @@ portable

set r v sets the value of r to v

val exchange : 'a. 'a t -> 'a @ portable contended -> 'a @ portable contended @@ portable

exchange r v sets the value of r to v, and returns the previous value

val compare_and_set : 'a. 'a t -> if_phys_equal_to:'a @ contended -> replace_with:'a @ portable contended -> Compare_failed_or_set_here.t @@ portable

compare_and_set r ~if_phys_equal_to ~replace_with sets the new value of r to replace_with only if its current value is physically equal to if_phys_equal_to -- the comparison and the set occur atomically. Returns Set_here if the value was set to replace_with by this call to compare_and_set, or Compare_failed if the current value was not physically equal to if_phys_equal_to and hence the atomic reference was left unchanged.

val compare_exchange : 'a. 'a t -> if_phys_equal_to:'a @ contended -> replace_with:'a @ portable contended -> 'a @ portable contended @@ portable

compare_exchange r ~if_phys_equal_to ~replace_with sets the new value of r to replace_with only if its current value is physically equal to if_phys_equal_to -- the comparison and the set occur atomically. Returns the previous value of r, or the current (unchanged) value if the comparison failed.

val update : 'a. 'a t @ local -> (pure_f:('a @ portable contended -> 'a @ portable contended) @ local -> unit) @ local @@ portable

update t ~pure_f atomically updates t to be the result of pure_f (get t). pure_f may be called multiple times, so should be free of side effects.

val get_and_update : 'a. 'a t @ local -> (pure_f:('a @ portable contended -> 'a @ portable contended) @ local -> 'a @ portable contended) @ local @@ portable

get_and_update t ~pure_f atomically updates t to be the result of pure_f (get t). pure_f may be called multiple times, so should be free of side effects. Returns the old value.

val fetch_and_add : int t -> int -> int @@ portable

fetch_and_add r n atomically increments the value of r by n, and returns the previous value (before the increment).

val add : int t -> int -> unit @@ portable

add r i atomically adds i to the value of r.

val sub : int t -> int -> unit @@ portable

sub r i atomically subtracts i from the value of r.

val logand : int t -> int -> unit @@ portable

logand r i atomically bitwise-ands i onto r.

val logor : int t -> int -> unit @@ portable

logor r i atomically bitwise-ands i onto r.

val logxor : int t -> int -> unit @@ portable

logxor r i atomically bitwise-xors i onto r.

val incr : int t @ local -> unit @@ portable

incr r atomically increments the value of r by 1.

val decr : int t @ local -> unit @@ portable

decr r atomically decrements the value of r by 1.

module Loc : sig ... end

Atomic "locations"

val contents : 'a. 'a t -> 'a Basement.Stdlib_shim.Modes.Portable.t Loc.t @ contended @@ portable

contents t is a Loc.t referring to the contents of the atomic ref t

module Expert : sig ... end