Tokio provides async equivalents of standard synchronization primitives. Unlike std types, these are designed to be held across .await points and integrate with the async task system.
All synchronization primitives in this module are runtime agnostic and can be freely moved between different Tokio runtime instances or even used from non-Tokio runtimes.
Creates a bounded multi-producer, single-consumer channel.Parameters:
buffer: Maximum number of messages that can be queued
Returns: A tuple of (Sender<T>, Receiver<T>)Example:
use tokio::sync::mpsc;#[tokio::main]async fn main() { let (tx, mut rx) = mpsc::channel(100); tokio::spawn(async move { for i in 0..10 { tx.send(i).await.unwrap(); } }); while let Some(msg) = rx.recv().await { println!("Received: {}", msg); }}
Creates a one-shot channel for sending a single value from one producer to one consumer.Example:
use tokio::sync::oneshot;#[tokio::main]async fn main() { let (tx, rx) = oneshot::channel(); tokio::spawn(async move { let result = expensive_computation().await; tx.send(result).unwrap(); }); let result = rx.await.unwrap(); println!("Got: {}", result);}
use tokio::sync::RwLock;#[tokio::main]async fn main() { let lock = RwLock::new(5); // Many reader locks can be held at once { let r1 = lock.read().await; let r2 = lock.read().await; assert_eq!(*r1, 5); assert_eq!(*r2, 5); } // read locks are dropped // Only one write lock can be held { let mut w = lock.write().await; *w += 1; assert_eq!(*w, 6); }}
Creates a new semaphore with the given number of permits.Example:
use tokio::sync::Semaphore;use std::sync::Arc;#[tokio::main]async fn main() { let semaphore = Arc::new(Semaphore::new(3)); let mut join_handles = Vec::new(); for i in 0..10 { let permit = semaphore.clone(); join_handles.push(tokio::spawn(async move { let _permit = permit.acquire().await.unwrap(); println!("Task {} is running", i); // Only 3 tasks run concurrently })); } for handle in join_handles { handle.await.unwrap(); }}
Creates a new barrier that waits for n tasks.Example:
use tokio::sync::Barrier;use std::sync::Arc;#[tokio::main]async fn main() { let barrier = Arc::new(Barrier::new(5)); let mut handles = Vec::new(); for i in 0..5 { let b = barrier.clone(); handles.push(tokio::spawn(async move { println!("Task {} before barrier", i); b.wait().await; println!("Task {} after barrier", i); })); } for handle in handles { handle.await.unwrap(); }}