module Nano_mutex:sig..end
Nano-mutexes can be faster than using OS-level mutexes because OCaml uses a global lock on the runtime, and requires all running OCaml code to hold the lock. The OCaml compiler only allows thread switches at certain points, and we can use that fact to get the atomic test-and-set used in the core of our implementaion without needing any primitive locking, essentially because we're protected by the OCaml global lock.
Here are some benchmarks comparing various mutexes available in OCaml:
|-------------------------------------------------------------|
| Name | Run time | S. dev. | Allocated |
|----------------------------+----------+---------+-----------+
| Caml.Mutex create | 247 ns | 0 ns | 3 |
| Caml.Mutex lock/unlock | 49 ns | 0 ns | 0 |
| Core.Mutex create | 698 ns | 0 ns | 3 |
| Core.Mutex lock/unlock | 49 ns | 0 ns | 0 |
| Nano_mutex create | 10 ns | 0 ns | 4 |
| Nano_mutex lock/unlock | 28 ns | 0 ns | 0 |
|-------------------------------------------------------------|
The benchmark code is in core/extended/lib_test/bench_nano_mutex.ml.
|--------------------+------------+------------+------------+
| | Caml.Mutex | Core.Mutex | Nano_mutex |
|--------------------+------------+------------+------------+
| recursive lock | undefined | error | error |
| unlocking unlocked | undefined | error | error |
| t1:lock t2:unlock | undefined | error | error |
|--------------------+------------+------------+------------+
type t
val invariant : t -> unitval create : unit -> tcreate () returns a new, unlocked mutex.val equal : t -> t -> boolequal is phys_equalval current_thread_has_lock : t -> boolcurrent_thread_has_lock t returns true iff the current thread has t locked.val lock : t -> unit Core_kernel.Std.Or_error.tlock t locks the mutex t, blocking until it can be locked. lock immediately
returns Error if the current thread already holds t.val lock_exn : t -> unitval try_lock : t -> [ `Acquired | `Not_acquired ] Core_kernel.Std.Or_error.ttry_lock t locks t if it can immediately do so. The result indicates whether
try_lock succeeded in acquiring the lock. try_lock returns Error if the current
thread already holds t.val try_lock_exn : t -> [ `Acquired | `Not_acquired ]val unlock : t -> unit Core_kernel.Std.Or_error.tunlock t unlocks t, if the current thread holds it. unlock returns Error if
the lock is not held by the calling thread.val unlock_exn : t -> unitval critical_section : t -> f:(unit -> 'a) -> 'aval sexp_of_t : t -> Sexplib.Sexp.tcreate () returns a new, unlocked mutex.equal is phys_equalcurrent_thread_has_lock t returns true iff the current thread has t locked.lock t locks the mutex t, blocking until it can be locked. lock immediately
returns Error if the current thread already holds t.try_lock t locks t if it can immediately do so. The result indicates whether
try_lock succeeded in acquiring the lock. try_lock returns Error if the current
thread already holds t.unlock t unlocks t, if the current thread holds it. unlock returns Error if
the lock is not held by the calling thread.