Crate parking_lot [] [src]

This library provides implementations of Mutex, RwLock, Condvar and Once that are smaller, faster and more flexible than those in the Rust standard library. It also exposes a low-level API for creating your own efficient synchronization primitives.

Features

The primitives provided by this library have several advantages over those in the Rust standard library:

  1. Mutex, Condvar and Once only require 1 byte of storage space, and RwLock only requires 1 word of storage space. On the other hand the standard library primitives require a dynamically allocated Box to hold OS-specific synchronization primitives. The small size of Mutex in particular encourages the use of fine-grained locks to increase parallelism.
  2. Since they consist of just a single atomic variable, have constant initializers and don't need destructors, these primitives can be used as static global variables. The standard library primitives require dynamic initialization and thus need to be lazily initialized with lazy_static!.
  3. Uncontended lock acquisition and release is done through fast inline paths which only require a single atomic operation.
  4. Microcontention (a contended lock with a short critical section) is efficiently handled by spinning a few times while trying to acquire a lock.
  5. The locks are adaptive and will suspend a thread after a few failed spin attempts. This makes the locks suitable for both long and short critical sections.

The parking lot

To keep these primitives small, all thread queuing and suspending functionality is offloaded to the parking lot. The idea behind this is based on the Webkit WTF::ParkingLot class, which essentially consists of a hash table mapping of lock addresses to queues of parked (sleeping) threads. The Webkit parking lot was itself inspired by Linux futexes, but it is more powerful since it allows invoking callbacks while holding a queue lock.

Parking refers to suspending the thread while simultaneously enqueuing it on a queue keyed by some address. Unparking refers to dequeuing a thread from a queue keyed by some address and resuming it. The parking lot API consists of just 3 functions:

unsafe fn park(key: usize,
               validate: &mut FnMut() -> bool,
               before_sleep: &mut FnMut(),
               timeout: Option<Instant>)
               -> bool

This function performs the following steps:

  1. Lock the queue associated with key.
  2. Call validate, if it returns false, unlock the queue and return.
  3. Add the current thread to the queue.
  4. Unlock the queue.
  5. Call before_sleep.
  6. Sleep until we are unparked or timeout is reached.
  7. Return true if we were unparked by another thread, false otherwise.
unsafe fn unpark_one(key: usize,
                     callback: &mut FnMut(UnparkResult))
                     -> UnparkResult

This function will unpark a single thread from the queue associated with key. The callback function is invoked while holding the queue lock but before the thread is unparked. The UnparkResult indicates whether the queue was empty and, if not, whether there are still threads remaining in the queue.

unsafe fn unpark_all(key: usize) -> usize

This function will unpark all threads in the queue associated with key. It returns the number of threads that were unparked.

Building custom synchronization primitives

Building custom synchronization primitives is very simple since parking_lot takes care of all the hard parts for you. The most commmon case for a custom primitive would be to integrate a Mutex inside another data type. Since a mutex only requires 2 bits, it can share space with other data. For example, one could create an ArcMutex type that combines the atomic reference count and the two mutex bits in the same atomic word.

Structs

Condvar

A Condition Variable

Mutex

A mutual exclusion primitive useful for protecting shared data

MutexGuard

An RAII implementation of a "scoped lock" of a mutex. When this structure is dropped (falls out of scope), the lock will be unlocked.

Once

A synchronization primitive which can be used to run a one-time initialization. Useful for one-time initialization for globals, FFI or related functionality.

OnceState

State yielded to the call_once_force method which can be used to query whether the Once was previously poisoned or not.

RwLock

A reader-writer lock

RwLockReadGuard

RAII structure used to release the shared read access of a lock when dropped.

RwLockWriteGuard

RAII structure used to release the exclusive write access of a lock when dropped.

WaitTimeoutResult

A type indicating whether a timed wait on a condition variable returned due to a time out or not.

Enums

UnparkResult

Result of an unpark_one operation.

Functions

park

Parks the current thread in the queue associated with the given key.

unpark_all

Unparks all threads in the queue associated with the given key.

unpark_one

Unparks one thread from the queue associated with the given key.