notification.rs
Overview
This file defines a Notification struct that provides a simple mechanism to signal and wait for notifications or updates within a concurrent environment. It uses atomic counters and synchronization primitives to allow multiple threads or asynchronous tasks to coordinate on changes or events signaled by instances of Notification.
The main purpose of this file is to manage notification state with minimal overhead and provide blocking wait functionality with optional timeouts, facilitating coordination between threads or components that require update awareness.
Struct: Notification
The Notification struct encapsulates a unique identifier and a shared notification state protected by synchronization primitives. It is designed to be cloned safely and used in a multithreaded context.
Fields
id: u32
A unique identifier assigned atomically at creation time. It distinguishes eachNotificationinstance.notifications: Arc<(parking_lot::Mutex<u32>, parking_lot::Condvar)>
A thread-safe, reference-counted tuple containing:A mutex guarding a
u32counter representing the current notification state (or version).A condition variable used to block and wake waiters when the notification state changes.
Implementation Details
The
idis generated using a static atomic counter (ID_COUNTER), ensuring unique ids across instances.The
notificationsfield leveragesparking_lotcrate'sMutexandCondvarfor efficient synchronization.The notification counter uses wrapping addition to handle potential overflow without panics.
The struct is
Clone-able, allowing multiple handles to the same notification state.
Important Notes
The file explicitly avoids implementing the Default trait for
Notificationto prevent accidental creation of multiple instances, as these should be limited.The synchronization primitives are wrapped in an
Arcto support cloning and shared ownership safely.
Methods
fn new() -> Self
Creates a new Notification instance.
Returns: A new instance of
Notificationwith a uniqueidand initialized notification state.Usage:
let notifier = Notification::new();
fn id(&self) -> u32
Returns the unique identifier of the Notification.
Returns:
u32representing the unique ID.Usage:
let id = notifier.id(); println!("Notification ID: {}", id);
fn touch(&mut self)
Signals an update by incrementing the internal notification counter and notifying all threads waiting on the condition variable.
Internally locks the mutex, increments the notification counter with wrapping addition, and calls
notify_allon the condition variable.Usage:
notifier.touch();
fn stamp(&self) -> u32
Returns the current notification counter value (stamp).
Locks the mutex and reads the current counter.
Returns: The
u32value representing the current notification state.Usage:
let version = notifier.stamp();
fn wait_for_updates(&mut self, stamp: u32)
Blocks the current thread until the notification counter changes from the given stamp.
Locks the mutex and waits on the condition variable while the stored counter equals the provided
stamp.This method blocks indefinitely until an update occurs.
Parameters:
stamp: u32— The notification counter value to wait to change from.
Usage:
let current_stamp = notifier.stamp(); notifier.wait_for_updates(current_stamp); // Blocks until updated
fn wait_for_updates_timeout(&mut self, stamp: u32, timeout: Duration)
Blocks the current thread until the notification counter changes from the given stamp or the specified timeout elapses.
Locks the mutex and waits on the condition variable with a timeout.
Parameters:
stamp: u32— The notification counter value to wait to change from.timeout: Duration— The maximum time to wait.
Usage:
use std::time::Duration; let current_stamp = notifier.stamp(); notifier.wait_for_updates_timeout(current_stamp, Duration::from_secs(5));
Interaction with Other Parts of the System
The
Notificationstruct can be used by various components requiring efficient notification signaling without busy-waiting.It relies on the
parking_lotcrate for synchronization primitives, which offers better performance compared to standard library mutexes and condition variables.The atomic unique ID counter ensures that multiple
Notificationinstances can be distinguished throughout the system.Typical usage scenarios include event signaling, update triggers in shared state, or inter-thread coordination.
The file does not depend on other parts of the system directly but offers a utility that can be integrated wherever notification signaling is required.
Implementation Details and Algorithms
Uses atomic operations (
AtomicU32) to generate unique IDs safely across threads.Employs a mutex-protected counter combined with a condition variable to implement a simple notification versioning system.
The notification counter increments with wrapping addition to avoid panic in the event of overflow.
Waiting methods use condition variable wait patterns that release the mutex while waiting and re-lock upon wake-up.
The
wait_for_updates_timeoutmethod adds a timeout mechanism allowing threads to resume after waiting for a specified duration even if no notification occurred.
Diagram
classDiagram
class Notification {
-id: u32
-notifications: Arc<(Mutex<u32>, Condvar)>
+new()
+id() u32
+touch()
+stamp() u32
+wait_for_updates(stamp: u32)
+wait_for_updates_timeout(stamp: u32, timeout: Duration)
}
Notification ..> AtomicU32 : uses for ID
Notification ..> Mutex : uses for notification counter
Notification ..> Condvar : uses for waiting/notification
This diagram illustrates the Notification struct's components and its relationships with synchronization primitives and atomic counters. The methods provide creation, identification, signaling, and waiting functionalities.