Skip to main content

ParkingLotMonitor

Struct ParkingLotMonitor 

Source
pub struct ParkingLotMonitor<T> { /* private fields */ }
Expand description

Shared state protected by a mutex and a condition variable.

ParkingLotMonitor is useful when callers need more than a short critical section. It models the classic monitor object pattern: one mutex protects the state, and one condition variable lets threads wait until that state changes. This is the same relationship used by parking_lot::Mutex and parking_lot::Condvar, but represented as one object so the condition variable is not accidentally used with unrelated state.

ParkingLotMonitor deliberately has two levels of API:

The underlying parking_lot mutex is not poisoned when a thread panics while holding the lock. This keeps monitor coordination state observable after panic unwinding.

§Difference from raw Mutex and Condvar

With raw parking_lot primitives, callers usually store two fields and manually keep them paired:

struct Shared {
    state: Mutex<State>,
    changed: Condvar,
}

ParkingLotMonitor<State> stores the same pair internally. A ParkingLotMonitorGuard is a wrapper around the parking_lot MutexGuard; it keeps the protected state locked and knows which monitor it belongs to, so its wait methods use the matching condition variable.

§Type Parameters

  • T - The state protected by this monitor.

§Example

use std::thread;

use qubit_lock::ArcParkingLotMonitor;

let monitor = ArcParkingLotMonitor::new(false);
let waiter_monitor = monitor.clone();

let waiter = thread::spawn(move || {
    waiter_monitor.wait_until(
        |ready| *ready,
        |ready| {
            *ready = false;
        },
    );
});

monitor.write(|ready| {
    *ready = true;
});
monitor.notify_all();

waiter.join().expect("waiter should finish");
assert!(!monitor.read(|ready| *ready));

Implementations§

Source§

impl<T> ParkingLotMonitor<T>

Source

pub fn new(state: T) -> Self

Creates a monitor protecting the supplied state value.

§Arguments
  • state - Initial state protected by the monitor.
§Returns

A monitor initialized with the supplied state.

§Example
use qubit_lock::ParkingLotMonitor;

let monitor = ParkingLotMonitor::new(0_u32);
assert_eq!(monitor.read(|n| *n), 0);
Source

pub fn lock(&self) -> ParkingLotMonitorGuard<'_, T>

Acquires the monitor and returns a guard for explicit state-machine code.

The returned ParkingLotMonitorGuard keeps the monitor mutex locked until the guard is dropped. It can also be passed through ParkingLotMonitorGuard::wait or ParkingLotMonitorGuard::wait_timeout to temporarily release the lock while waiting on this monitor’s condition variable.

§Returns

A guard that provides read and write access to the protected state.

§Example
use qubit_lock::ParkingLotMonitor;

let monitor = ParkingLotMonitor::new(1);
{
    let mut value = monitor.lock();
    *value += 1;
}

assert_eq!(monitor.read(|value| *value), 2);
Source

pub fn read<R, F>(&self, f: F) -> R
where F: FnOnce(&T) -> R,

Acquires the monitor and reads the protected state.

The closure runs while the mutex is held. Keep the closure short and do not call code that may block for a long time.

§Arguments
  • f - Closure that receives an immutable reference to the state.
§Returns

The value returned by the closure.

§Example
use qubit_lock::ParkingLotMonitor;

let monitor = ParkingLotMonitor::new(10_i32);
let n = monitor.read(|x| *x);
assert_eq!(n, 10);
Source

pub fn write<R, F>(&self, f: F) -> R
where F: FnOnce(&mut T) -> R,

Acquires the monitor and mutates the protected state.

The closure runs while the mutex is held. This method only changes the state; callers should explicitly call Self::notify_one or Self::notify_all after changing a condition that waiters may be observing.

§Arguments
  • f - Closure that receives a mutable reference to the state.
§Returns

The value returned by the closure.

§Example
use qubit_lock::ParkingLotMonitor;

let monitor = ParkingLotMonitor::new(String::new());
let len = monitor.write(|s| {
    s.push_str("hi");
    s.len()
});
assert_eq!(len, 2);
Source

pub fn write_notify_one<R, F>(&self, f: F) -> R
where F: FnOnce(&mut T) -> R,

Acquires the monitor, mutates the protected state, and wakes one waiter.

The closure runs while the mutex is held. After the closure returns, the mutex guard is dropped and one thread waiting on this monitor’s condition variable is notified. This is a convenience method for the common “update state, then notify one waiter” pattern.

If f panics, the panic is propagated and no notification is sent.

§Arguments
  • f - Closure that receives a mutable reference to the state.
§Returns

The value returned by the closure.

§Example
use qubit_lock::ParkingLotMonitor;

let monitor = ParkingLotMonitor::new(Vec::<i32>::new());
let len = monitor.write_notify_one(|items| {
    items.push(7);
    items.len()
});

assert_eq!(len, 1);
Source

pub fn write_notify_all<R, F>(&self, f: F) -> R
where F: FnOnce(&mut T) -> R,

Acquires the monitor, mutates the protected state, and wakes all waiters.

The closure runs while the mutex is held. After the closure returns, the mutex guard is dropped and all threads waiting on this monitor’s condition variable are notified. This is a convenience method for state changes that may allow multiple waiters to make progress.

If f panics, the panic is propagated and no notification is sent.

§Arguments
  • f - Closure that receives a mutable reference to the state.
§Returns

The value returned by the closure.

§Example
use qubit_lock::ParkingLotMonitor;

let monitor = ParkingLotMonitor::new(false);
let ready = monitor.write_notify_all(|ready| {
    *ready = true;
    *ready
});

assert!(ready);
Source

pub fn wait(&self)

Waits for a notification without checking state.

This method locks the monitor, waits once on the condition variable, and returns after the wait is woken. Most coordination code should prefer Self::wait_while, Self::wait_until, or an explicit ParkingLotMonitorGuard loop that rechecks protected state.

This method may block indefinitely if no notification is sent.

Source

pub fn wait_for(&self, timeout: Duration) -> WaitTimeoutStatus

Waits for a notification or timeout without checking state.

This convenience method locks the monitor, waits once on the condition variable, and returns why the timed wait completed. It is useful only when the caller genuinely needs a notification wait without inspecting state before or after the wait. Most coordination code should prefer Self::wait_while, Self::wait_until, or the explicit ParkingLotMonitorGuard::wait_timeout loop.

WaitTimeoutStatus::Woken means the condition variable was notified, but it does not prove that the protected state changed in a useful way.

§Arguments
  • timeout - Maximum duration to wait for a notification.
§Returns

WaitTimeoutStatus::Woken if the wait returned before the timeout, or WaitTimeoutStatus::TimedOut if the timeout elapsed.

§Example
use std::time::Duration;

use qubit_lock::{ParkingLotMonitor, WaitTimeoutStatus};

let monitor = ParkingLotMonitor::new(false);
let status = monitor.wait_for(Duration::from_millis(1));

assert_eq!(status, WaitTimeoutStatus::TimedOut);
Source

pub fn wait_while<R, P, F>(&self, waiting: P, f: F) -> R
where P: FnMut(&T) -> bool, F: FnOnce(&mut T) -> R,

Waits while a predicate remains true, then mutates the protected state.

This is the monitor equivalent of the common while condition { wait } guarded-suspension pattern. The predicate is evaluated while holding the mutex. If it returns true, the current thread waits on the condition variable and atomically releases the mutex. After a notification, the mutex is reacquired and the predicate is evaluated again. When the predicate returns false, f runs while the mutex is still held.

This method may block indefinitely if no thread changes the state so that waiting becomes false and sends a notification.

§Arguments
  • waiting - Predicate that returns true while the caller should keep waiting.
  • f - Closure that receives mutable access after waiting is no longer required.
§Returns

The value returned by f.

§Example
use std::{
    sync::Arc,
    thread,
};

use qubit_lock::ParkingLotMonitor;

let monitor = Arc::new(ParkingLotMonitor::new(Vec::<i32>::new()));
let worker_monitor = Arc::clone(&monitor);

let worker = thread::spawn(move || {
    worker_monitor.wait_while(
        |items| items.is_empty(),
        |items| items.pop().expect("item should be ready"),
    )
});

monitor.write(|items| items.push(7));
monitor.notify_one();

assert_eq!(worker.join().expect("worker should finish"), 7);
Source

pub fn wait_until<R, P, F>(&self, ready: P, f: F) -> R
where P: FnMut(&T) -> bool, F: FnOnce(&mut T) -> R,

Waits until the protected state satisfies a predicate, then mutates it.

This is the positive-predicate counterpart of Self::wait_while. The predicate is evaluated while holding the mutex. If it returns false, the current thread waits on the condition variable and atomically releases the mutex. After a notification, the mutex is reacquired and the predicate is evaluated again. When the predicate returns true, f runs while the mutex is still held.

This method may block indefinitely if no thread changes the state to satisfy the predicate and sends a notification.

§Arguments
  • ready - Predicate that returns true when the state is ready.
  • f - Closure that receives mutable access to the ready state.
§Returns

The value returned by f after the predicate has become true.

§Example
use std::{
    sync::Arc,
    thread,
};

use qubit_lock::ParkingLotMonitor;

let monitor = Arc::new(ParkingLotMonitor::new(false));
let waiter_monitor = Arc::clone(&monitor);

let waiter = thread::spawn(move || {
    waiter_monitor.wait_until(
        |ready| *ready,
        |ready| {
            *ready = false;
            "done"
        },
    )
});

monitor.write(|ready| *ready = true);
monitor.notify_one();

assert_eq!(waiter.join().expect("waiter should finish"), "done");
Source

pub fn wait_while_for<R, P, F>( &self, timeout: Duration, waiting: P, f: F, ) -> WaitTimeoutResult<R>
where P: FnMut(&T) -> bool, F: FnOnce(&mut T) -> R,

Waits while a predicate remains true, with an overall time limit.

This method is the timeout-aware form of Self::wait_while. It keeps rechecking waiting under the monitor lock and waits only for the remaining portion of timeout. If waiting becomes false before the timeout expires, f runs while the lock is still held. If the timeout expires first, the closure is not called.

Timeout status alone is not used as proof that the predicate is still true; the predicate is always rechecked under the lock.

§Arguments
  • timeout - Maximum total duration to wait.
  • waiting - Predicate that returns true while the caller should continue waiting.
  • f - Closure that receives mutable access when waiting is no longer required.
§Returns

WaitTimeoutResult::Ready with the value returned by f when the predicate stops blocking before the timeout. Returns WaitTimeoutResult::TimedOut when the timeout expires first.

§Example
use std::time::Duration;

use qubit_lock::{ParkingLotMonitor, WaitTimeoutResult};

let monitor = ParkingLotMonitor::new(Vec::<i32>::new());
let result = monitor.wait_while_for(
    Duration::from_millis(1),
    |items| items.is_empty(),
    |items| items.pop(),
);

assert_eq!(result, WaitTimeoutResult::TimedOut);
Source

pub fn wait_until_for<R, P, F>( &self, timeout: Duration, ready: P, f: F, ) -> WaitTimeoutResult<R>
where P: FnMut(&T) -> bool, F: FnOnce(&mut T) -> R,

Waits until a predicate becomes true, with an overall time limit.

This is the positive-predicate counterpart of Self::wait_while_for. If ready becomes true before the timeout expires, f runs while the monitor lock is still held. If the timeout expires first, the closure is not called.

Timeout status alone is not used as proof that the predicate is still false; the predicate is always rechecked under the lock.

§Arguments
  • timeout - Maximum total duration to wait.
  • ready - Predicate that returns true when the caller may continue.
  • f - Closure that receives mutable access to the ready state.
§Returns

WaitTimeoutResult::Ready with the value returned by f when the predicate becomes true before the timeout. Returns WaitTimeoutResult::TimedOut when the timeout expires first.

§Example
use std::{
    sync::Arc,
    thread,
    time::Duration,
};

use qubit_lock::{ParkingLotMonitor, WaitTimeoutResult};

let monitor = Arc::new(ParkingLotMonitor::new(false));
let waiter_monitor = Arc::clone(&monitor);

let waiter = thread::spawn(move || {
    waiter_monitor.wait_until_for(
        Duration::from_secs(1),
        |ready| *ready,
        |ready| {
            *ready = false;
            5
        },
    )
});

monitor.write(|ready| *ready = true);
monitor.notify_one();

assert_eq!(
    waiter.join().expect("waiter should finish"),
    WaitTimeoutResult::Ready(5),
);
Source

pub fn notify_one(&self)

Wakes one thread waiting on this monitor’s condition variable.

Notifications do not carry state by themselves. A waiting thread only proceeds safely after rechecking the protected state. Call this after changing state that may make one waiter able to continue.

§Example
use std::thread;

use qubit_lock::ArcParkingLotMonitor;

let monitor = ArcParkingLotMonitor::new(0_u32);
let waiter = {
    let m = monitor.clone();
    thread::spawn(move || {
        m.wait_until(|n| *n > 0, |n| {
            *n -= 1;
        });
    })
};

monitor.write(|n| *n = 1);
monitor.notify_one();
waiter.join().expect("waiter should finish");
Source

pub fn notify_all(&self)

Wakes all threads waiting on this monitor’s condition variable.

Notifications do not carry state by themselves. Every awakened thread must recheck the protected state before continuing. Call this after a state change that may allow multiple waiters to make progress.

§Example
use std::thread;

use qubit_lock::ArcParkingLotMonitor;

let monitor = ArcParkingLotMonitor::new(false);
let mut handles = Vec::new();
for _ in 0..2 {
    let m = monitor.clone();
    handles.push(thread::spawn(move || {
        m.wait_until(|ready| *ready, |_| ());
    }));
}

monitor.write(|ready| *ready = true);
monitor.notify_all();
for h in handles {
    h.join().expect("waiter should finish");
}

Trait Implementations§

Source§

impl<T> AsRef<ParkingLotMonitor<T>> for ArcParkingLotMonitor<T>

Source§

fn as_ref(&self) -> &ParkingLotMonitor<T>

Returns a reference to the underlying monitor.

This is useful when callers need an explicit ParkingLotMonitor reference while keeping the cloneable ArcParkingLotMonitor handle.

Source§

impl<T> ConditionWaiter for ParkingLotMonitor<T>

Source§

fn wait_until<R, P, F>(&self, predicate: P, action: F) -> R
where P: FnMut(&Self::State) -> bool, F: FnOnce(&mut Self::State) -> R,

Blocks until the predicate becomes true, then runs the action.

Source§

fn wait_while<R, P, F>(&self, predicate: P, action: F) -> R
where P: FnMut(&Self::State) -> bool, F: FnOnce(&mut Self::State) -> R,

Blocks while the predicate remains true, then runs the action.

Source§

type State = T

State protected by the monitor.
Source§

impl<T: Default> Default for ParkingLotMonitor<T>

Source§

fn default() -> Self

Creates a monitor containing T::default().

§Returns

A monitor protecting the default value for T.

§Example
use qubit_lock::ParkingLotMonitor;

let monitor: ParkingLotMonitor<String> = ParkingLotMonitor::default();
assert!(monitor.read(|s| s.is_empty()));
Source§

impl<T> From<T> for ParkingLotMonitor<T>

Source§

fn from(value: T) -> Self

Creates a monitor from an initial state value.

§Arguments
  • value - Initial state protected by the monitor.
§Returns

A monitor initialized with value.

Source§

impl<T> NotificationWaiter for ParkingLotMonitor<T>

Source§

fn wait(&self)

Blocks until a notification wakes this waiter.

Source§

impl<T> Notifier for ParkingLotMonitor<T>

Source§

fn notify_one(&self)

Wakes one thread waiting on this monitor.

Source§

fn notify_all(&self)

Wakes all threads waiting on this monitor.

Source§

impl<T> TimeoutConditionWaiter for ParkingLotMonitor<T>

Source§

fn wait_until_for<R, P, F>( &self, timeout: Duration, predicate: P, action: F, ) -> WaitTimeoutResult<R>
where P: FnMut(&Self::State) -> bool, F: FnOnce(&mut Self::State) -> R,

Blocks until the predicate becomes true or the timeout expires.

Source§

fn wait_while_for<R, P, F>( &self, timeout: Duration, predicate: P, action: F, ) -> WaitTimeoutResult<R>
where P: FnMut(&Self::State) -> bool, F: FnOnce(&mut Self::State) -> R,

Blocks while the predicate remains true or until the timeout expires.

Source§

impl<T> TimeoutNotificationWaiter for ParkingLotMonitor<T>

Source§

fn wait_for(&self, timeout: Duration) -> WaitTimeoutStatus

Blocks until a notification wakes this waiter or the timeout expires.

Auto Trait Implementations§

§

impl<T> !Freeze for ParkingLotMonitor<T>

§

impl<T> !RefUnwindSafe for ParkingLotMonitor<T>

§

impl<T> Send for ParkingLotMonitor<T>
where T: Send,

§

impl<T> Sync for ParkingLotMonitor<T>
where T: Send,

§

impl<T> Unpin for ParkingLotMonitor<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for ParkingLotMonitor<T>
where T: UnsafeUnpin,

§

impl<T> UnwindSafe for ParkingLotMonitor<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Monitor for T