Published on

Send与Sync:代码示例

1. Basic Send Example: Moving Data Between Threads

use std::thread;

fn main() {
    let data = vec![1, 2, 3]; // Vec<i32> is Send + Sync
    
    let handle = thread::spawn(move || {
        println!("Data in thread: {:?}", data); // Ownership moved here
    });
    
    handle.join().unwrap();
}

Key Point: Vec<i32> implements Send, so its ownership can be transferred across threads.


2. Sync Example: Shared Immutable Data with Arc

use std::sync::Arc;
use std::thread;

fn main() {
    let shared_data = Arc::new(42); // Arc<T> requires T: Send + Sync
    
    let handles: Vec<_> = (0..3).map(|_| {
        let data = Arc::clone(&shared_data);
        thread::spawn(move || {
            println!("Thread sees: {}", data); // Shared immutable reference
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}

Key Point: Arc<T> allows shared read-only access across threads (Sync behavior).


3. Thread-Safe Mutability with Mutex (Send + Sync)

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0)); // Mutex<T> requires T: Send
    
    let handles: Vec<_> = (0..10).map(|_| {
        let counter = Arc::clone(&counter);
        thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1; // Safe mutable access
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
    
    println!("Result: {}", *counter.lock().unwrap());
}

Key Points:

  • Mutex<T> implements Sync when T: Send
  • Arc<Mutex<T>> is a classic thread-safe interior mutability pattern

4. Non-Send Type Example (Rc)

use std::rc::Rc;
use std::thread;

fn main() {
    let data = Rc::new(42);
    
    // This would fail to compile:
    // thread::spawn(move || {
    //     println!("{}", data); // ERROR: Rc<i32> cannot be sent between threads
    // });
}

Fix: Replace Rc with Arc to make it Send.


5. Custom Send + Sync Implementation (Advanced)

use std::marker::PhantomData;

struct MyThreadSafePtr<T: Send>(*const T);

// SAFETY: We guarantee pointer access is synchronized externally
unsafe impl<T: Send> Send for MyThreadSafePtr<T> {}
unsafe impl<T: Send> Sync for MyThreadSafePtr<T> {}

fn main() {
    let val = 10;
    let ptr = MyThreadSafePtr(&val as *const i32);
    
    thread::spawn(move || {
        // Can move to thread because we implemented Send
        println!("Pointer in thread: {:p}", ptr.0);
    }).join().unwrap();
}

Key Points:

  • Manual unsafe impl requires careful safety guarantees
  • PhantomData often used for generic types

6. Conditional Send/Sync with Generic Types

use std::marker::PhantomData;

struct Container<T> {
    data: T,
    _marker: PhantomData<*const ()>, // Affects auto-traits
}

// Only Send when T is Send
unsafe impl<T: Send> Send for Container<T> {}
// Only Sync when T is Sync
unsafe impl<T: Sync> Sync for Container<T> {}

fn main() {
    let container = Container {
        data: 42,
        _marker: PhantomData,
    };
    
    thread::spawn(move || {
        println!("{}", container.data); // Works because i32 is Send
    }).join().unwrap();
}

7. Channel Communication (Send in Action)

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    
    thread::spawn(move || {
        let data = vec![1, 2, 3];
        tx.send(data).unwrap(); // Moving ownership through channel
    });
    
    println!("Received: {:?}", rx.recv().unwrap());
}

Key Point: Channels require their contents to implement Send.


8. Parallel Processing with Rayon (Sync Showcase)

use rayon::prelude::*;

fn main() {
    let data = vec![1, 2, 3, 4, 5];
    
    let sum: i32 = data.par_iter() // Requires &[T] where T: Sync
        .map(|x| x * 2)
        .sum();
    
    println!("Parallel sum: {}", sum);
}

Key Takeaways:

  1. Send enables ownership transfer between threads
  2. Sync enables shared references (&T) across threads
  3. Most Rust types are Send/Sync by default
  4. Composition matters - compound types inherit Send/Sync from components
  5. Thread-safe patterns combine Arc (Sync) with Mutex/RwLock (Send)

THE END