### Async Semaphore for Limiting Concurrent Operations in Rust Source: https://context7.com/smol-rs/async-lock/llms.txt Implements a counting semaphore to limit the number of concurrent operations accessing a shared resource. It allows acquiring permits, blocking if the limit is reached, and dynamically adding more permits. `try_acquire` attempts to get a permit without blocking. ```rust use async_lock::Semaphore; use std::sync::Arc; async fn example() { // Allow only 3 concurrent operations let semaphore = Arc::new(Semaphore::new(3)); let mut tasks = vec![]; for i in 0..10 { let sem = semaphore.clone(); tasks.push(async_std::task::spawn(async move { // Acquire a permit (blocks if limit reached) let _guard = sem.acquire().await; println!("Task {} acquired permit", i); // Simulate work async_std::task::sleep(std::time::Duration::from_millis(100)).await; println!("Task {} releasing permit", i); // Permit automatically released when guard drops })); } // Wait for all tasks for task in tasks { task.await; } // Dynamically add permits semaphore.add_permits(2); // Try without blocking if let Some(_guard) = semaphore.try_acquire() { println!("Acquired permit immediately"); } } ``` -------------------------------- ### Async RwLock for Reader-Writer Access in Rust Source: https://context7.com/smol-rs/async-lock/llms.txt Provides an asynchronous Reader-Writer Lock (RwLock) with a write-preferring strategy. It allows multiple concurrent readers or a single exclusive writer. It also supports upgradable read locks that can be promoted to write locks. ```rust use async_lock::RwLock; use std::sync::Arc; async fn example() { let lock = Arc::new(RwLock::new(vec![1, 2, 3])); // Multiple readers can access simultaneously let reader1 = lock.clone(); let reader2 = lock.clone(); let read_task1 = async_std::task::spawn(async move { let data = reader1.read().await; println!("Reader 1: {:?}", *data); }); let read_task2 = async_std::task::spawn(async move { let data = reader2.read().await; println!("Reader 2: {:?}", *data); }); // Wait for readers to finish read_task1.await; read_task2.await; // Exclusive write access let mut writer = lock.write().await; writer.push(4); drop(writer); // Upgradable read lock can be promoted to write lock let upgradable = lock.upgradable_read().await; println!("Current data: {:?}", *upgradable); let mut writer = async_lock::RwLockUpgradableReadGuard::upgrade(upgradable).await; writer.push(5); } ``` -------------------------------- ### OnceCell Lazy Initialization - Rust Source: https://context7.com/smol-rs/async-lock/llms.txt OnceCell provides one-time lazy initialization, suitable for async operations. Multiple tasks can call `get_or_init`, but the initialization function runs only once. It can be initialized via `get_or_init` or `set`. ```rust use async_lock::OnceCell; use std::sync::Arc; struct Config { database_url: String, api_key: String, } async fn load_config() -> Config { // Simulate expensive async initialization async_std::task::sleep(std::time::Duration::from_secs(1)).await; Config { database_url: "postgres://localhost/db".to_string(), api_key: "secret_key".to_string(), } } async fn example() { let config_cell = Arc::new(OnceCell::new()); // Multiple tasks can call get_or_init, but load_config runs once let mut tasks = vec![]; for i in 0..5 { let cell = config_cell.clone(); tasks.push(async_std::task::spawn(async move { let config = cell.get_or_init(|| load_config()).await; println!("Task {} got config: {}", i, config.database_url); })); } for task in tasks { task.await; } // Check if initialized if config_cell.is_initialized() { let config = config_cell.get().unwrap(); println!("Config loaded: {}", config.api_key); } // Can also use set directly let another_cell = OnceCell::new(); match another_cell.set(Config { database_url: "test".to_string(), api_key: "key".to_string(), }).await { Ok(_) => println!("Set successfully"), Err(old_value) => println!("Already initialized"), } } ``` -------------------------------- ### Barrier Synchronization - Rust Source: https://context7.com/smol-rs/async-lock/llms.txt A Barrier synchronizes multiple tasks, blocking them until all reach a specific point, then releasing them simultaneously. It requires the number of participants upon creation. Each task can check if it was the last to arrive using `is_leader()`. ```rust use async_lock::Barrier; use std::sync::Arc; async fn example() { let barrier = Arc::new(Barrier::new(3)); let mut tasks = vec![]; for i in 0..3 { let b = barrier.clone(); tasks.push(async_std::task::spawn(async move { println!("Task {} starting work", i); // Simulate different work durations async_std::task::sleep( std::time::Duration::from_millis(i * 100) ).await; println!("Task {} waiting at barrier", i); let result = b.wait().await; // Check if this task was the last to arrive if result.is_leader() { println!("Task {} was the leader!", i); } println!("Task {} passed barrier", i); })); } // All tasks will print "passed barrier" at roughly the same time for task in tasks { task.await; } } ``` -------------------------------- ### Async Mutex for Mutual Exclusion in Rust Source: https://context7.com/smol-rs/async-lock/llms.txt Implements an asynchronous Mutex for mutual exclusion. It allows only one task to access protected data at a time and ensures eventual fairness to prevent starvation. The guard returned by `lock().await` automatically releases the mutex when dropped. ```rust use async_lock::Mutex; use std::sync::Arc; async fn example() { let mutex = Arc::new(Mutex::new(0)); let mutex_clone = mutex.clone(); // Spawn multiple tasks that increment a shared counter let task1 = async_std::task::spawn(async move { for _ in 0..100 { let mut guard = mutex_clone.lock().await; *guard += 1; // Guard is automatically released when dropped } }); // Try to acquire without waiting match mutex.try_lock() { Some(mut guard) => { *guard += 10; drop(guard); } None => println!("Mutex is locked"), } task1.await; let final_value = mutex.lock().await; println!("Final value: {}", *final_value); } ``` -------------------------------- ### Arc-based Guards for Mutex - Rust Source: https://context7.com/smol-rs/async-lock/llms.txt The async-lock Mutex supports Arc-based ownership for guards, allowing them to be moved across tasks. `lock_arc()` returns a guard that owns a clone of the Arc, enabling its use in other asynchronous tasks. ```rust use async_lock::Mutex; use std::sync::Arc; async fn example() { let mutex = Arc::new(Mutex::new(vec![1, 2, 3])); // Regular guard is tied to the mutex's lifetime let guard = mutex.lock().await; // Arc guard owns a clone of the Arc let arc_guard = mutex.lock_arc().await; // Can send arc_guard to another task let task = async_std::task::spawn(async move { println!("Data in other task: {:?}", *arc_guard); // Guard unlocks when dropped in this task }); task.await; } ``` -------------------------------- ### Blocking Mutex Variants for Synchronous Code - Rust Source: https://context7.com/smol-rs/async-lock/llms.txt All synchronization primitives in async-lock provide `_blocking` variants for use in synchronous code, such as standard threads. These methods prevent deadlocks when called from a non-async context. ```rust use async_lock::Mutex; use std::sync::Arc; use std::thread; fn example() { let mutex = Arc::new(Mutex::new(0)); let mutex_clone = mutex.clone(); // Use blocking methods in regular threads let handle = thread::spawn(move || { let mut guard = mutex_clone.lock_blocking(); *guard += 1; }); handle.join().unwrap(); let value = mutex.lock_blocking(); println!("Value: {}", *value); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.