# Synchronization Primitives Guide

# Rust & Tokio Synchronization Primitives Guide

When building concurrent or asynchronous applications in Rust, choosing the right synchronization primitive is critical for performance and safety. Below is a comprehensive guide to the standard library (`std`) and Tokio synchronization tools.

### 📊 Quick Comparison Table

| Primitive | Ecosystem | Concurrency Pattern | Best Use Case |
| :--- | :--- | :--- | :--- |
| `std::sync::Arc` | Std | Shared Ownership | Sharing memory safely across multiple threads. Almost always wraps another primitive (e.g., `Arc<Mutex<T>>`). |
| `std::sync::Mutex` | Std | Exclusive Access | Brief, synchronous locks (pushing to a `Vec`, updating a number). **Never hold across an `.await`.** |
| `tokio::sync::Mutex` | Tokio | Async Exclusive Access | When you absolutely *must* hold a lock while waiting for an asynchronous operation (across an `.await`). |
| `std::sync::RwLock` | Std | Multi-Read / Single-Write | High-Read / Low-Write patterns. Allows dozens of threads to read simultaneously without blocking. |
| `tokio::sync::watch` | Tokio | SPMC State Broadcast | Broadcasting the *latest* configuration or status. Only the newest value is kept; slow receivers drop old data. |
| `tokio::sync::broadcast` | Tokio | MPMC Event Stream | Pub/Sub systems like chat rooms where multiple listeners must receive *every* message in order. |

---

### 1. The Standard `Arc<Mutex<T>>` (Synchronous Mutability)
Use `std::sync::Mutex` when you need to safely mutate data across threads, and the mutation is fast and synchronous. 

**Rule of Thumb:** It is significantly faster than Tokio's Mutex. Use it as long as you do not call `.await` while the lock is locked.

```rust
use std::sync::{Arc, Mutex};
use std::thread;

// Wrap our data in a Mutex (for safe mutation) and Arc (for safe sharing)
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];

for _ in 0..10 {
    let counter_clone = Arc::clone(&counter);
    
    let handle = thread::spawn(move || {
        // 1. Lock the mutex
        let mut num = counter_clone.lock().unwrap();
        // 2. Modify the value quickly
        *num += 1; 
        // 3. Lock is automatically released here when `num` goes out of scope
    });
    
    handles.push(handle);
}

for handle in handles {
    handle.join().unwrap();
}

println!("Final count: {}", *counter.lock().unwrap());
```

---

### 2. The `tokio::sync::Mutex` (Async Mutability)
Use Tokio's Mutex **only** when your lock must remain active while the thread yields to the async runtime (i.e., across an `.await` boundary). It is heavier because it requires internal bookkeeping to allow other tasks to run on the thread while the current task sleeps.

```rust
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() {
    let shared_state = Arc::new(Mutex::new(String::from("Idle")));
    
    let state_clone = Arc::clone(&shared_state);
    tokio::spawn(async move {
        // Acquire the async lock
        let mut state = state_clone.lock().await;
        *state = String::from("Fetching Data...");
        
        // SAFE: Holding a Tokio Mutex across an .await point
        sleep(Duration::from_secs(2)).await; 
        
        *state = String::from("Complete");
    });
}
```

---

### 3. The `Arc<RwLock<T>>` (High-Read / Low-Write)
If you have a configuration struct or global state that is read constantly by many UI components or threads, but only updated occasionally, `RwLock` maximizes performance by allowing parallel reads.

```rust
use std::sync::{Arc, RwLock};
use std::thread;

let config = Arc::new(RwLock::new(vec!["dark_mode", "auto_save"]));

// READER THREAD 1
let config_read1 = Arc::clone(&config);
thread::spawn(move || {
    let read_guard = config_read1.read().unwrap();
    println!("Thread 1 sees: {:?}", *read_guard);
});

// READER THREAD 2 (Can run at the exact same time as Thread 1)
let config_read2 = Arc::clone(&config);
thread::spawn(move || {
    let read_guard = config_read2.read().unwrap();
    println!("Thread 2 sees: {:?}", *read_guard);
});

// WRITER THREAD (Will block until all readers are finished)
let config_write = Arc::clone(&config);
thread::spawn(move || {
    let mut write_guard = config_write.write().unwrap();
    write_guard.push("telemetry_enabled");
});
```

---

### 4. Tokio Watch Channel (`tokio::sync::watch`)
A highly optimized Single-Producer, Multi-Consumer (SPMC) channel. Perfect for broadcasting state where receivers only care about the *latest* data.

```rust
use tokio::sync::watch;

#[tokio::main]
async fn main() {
    // Initialize with a default state
    let (tx, mut rx1) = watch::channel("Offline");
    
    // Receivers can be cloned incredibly cheaply
    let mut rx2 = rx1.clone();

    tokio::spawn(async move {
        // Wait for the state to change
        while rx1.changed().await.is_ok() {
            println!("UI Component 1 Update: {}", *rx1.borrow());
        }
    });

    tokio::spawn(async move {
        while rx2.changed().await.is_ok() {
            println!("UI Component 2 Update: {}", *rx2.borrow());
        }
    });

    // Sender updates the state instantly
    tx.send("Connecting...").unwrap();
    tx.send("Online").unwrap(); 
}
```