Rust Logoparking_lot

parking_lot is a popular Rust library that offers highly optimized and feature-rich synchronization primitives, serving as a powerful alternative to the `std::sync` module. Its core goal is to provide superior performance, reduced memory consumption, and enhanced functionality for concurrent programming tasks.

Key advantages of `parking_lot` include:
* Performance: Often outperforms `std::sync` primitives due to advanced algorithms like adaptive spinning, futexes (on Linux), and optimized internal designs. This makes it a preferred choice for high-contention scenarios.
* Memory Efficiency: Locks from `parking_lot` typically consume less memory compared to their `std::sync` counterparts, which can be beneficial in applications with a large number of locks.
* Extended Features: It provides functionality not present in `std::sync`, such as `RwLockUpgradableReadGuard`, which allows a read lock to be upgraded to a write lock, and `MutexGuard::map` / `RwLockReadGuard::map`, which enable mapping a guard to a sub-field without re-locking.
* Deadlock Detection (Debug Builds): In debug configurations, `parking_lot` can optionally assist in detecting potential deadlocks, a valuable feature for debugging complex concurrent systems.

The primary synchronization primitives offered by `parking_lot` are:
* `parking_lot::Mutex`: A mutual exclusion lock, similar to `std::sync::Mutex`, but generally faster and smaller. It ensures that only one thread can access the protected data at any given time.
* `parking_lot::RwLock`: A reader-writer lock, akin to `std::sync::RwLock`. It allows multiple readers to access the data concurrently but restricts access to a single writer (and no readers) when a write lock is held. `parking_lot`'s version is particularly noted for its performance and the `UpgradableReadGuard` feature.
* `parking_lot::Condvar`: A condition variable, used in conjunction with `Mutex` to allow threads to wait until a certain condition is met and be notified by other threads.

parking_lot is widely used in high-performance Rust applications and libraries where fine-grained control over synchronization and optimal resource utilization are critical.

Example Code

use parking_lot::{Mutex, RwLock};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

fn main() {
    println!("--- parking_lot::Mutex Example ---");
    // Create a shared counter protected by a Mutex
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    // Spawn multiple threads to increment the counter
    for i in 0..5 {
        let counter_clone = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            let mut num = counter_clone.lock(); // Acquire the mutex lock
            *num += 1;
            println!("Thread {} incremented counter to {}", i, *num);
            // The lock is automatically released when 'num' (MutexGuard) goes out of scope
        }));
    }

    // Wait for all threads to complete
    for handle in handles.drain(..) {
        handle.join().unwrap();
    }
    println!("Final counter value: {}", *counter.lock());

    println!("\n--- parking_lot::RwLock Example ---");
    // Create shared data (a vector) protected by an RwLock
    let data = Arc::new(RwLock::new(vec![1, 2, 3]));
    let mut handles = vec![];

    // Spawn multiple reader threads
    for i in 0..3 {
        let data_clone = Arc::clone(&data);
        handles.push(thread::spawn(move || {
            let reader_guard = data_clone.read(); // Acquire a read lock
            println!("Reader {}: Data = {:?}", i, *reader_guard);
            thread::sleep(Duration::from_millis(10)); // Simulate some work
            // The read lock is automatically released
        }));
    }

    // Spawn a writer thread
    let data_clone_writer = Arc::clone(&data);
    handles.push(thread::spawn(move || {
        let mut writer_guard = data_clone_writer.write(); // Acquire a write lock
        println!("Writer: Modifying data...");
        writer_guard.push(4);
        writer_guard[0] = 100; // Modify an existing element
        thread::sleep(Duration::from_millis(20)); // Simulate some work
        println!("Writer: Data modified to {:?}", *writer_guard);
        // The write lock is automatically released
    }));

    // Spawn more reader threads (these might run before or after the writer, depending on scheduling)
    for i in 3..5 {
        let data_clone = Arc::clone(&data);
        handles.push(thread::spawn(move || {
            let reader_guard = data_clone.read(); // Acquire a read lock
            println!("Reader {}: Data = {:?}", i, *reader_guard);
            // The read lock is automatically released
        }));
    }

    // Wait for all threads to complete
    for handle in handles {
        handle.join().unwrap();
    }
    println!("Final data after all operations: {:?}", *data.read());
}