Skip to content

threads.rs

文件信息

  • 📄 原文件:01_threads.rs
  • 🔤 语言:rust

完整代码

rust
// ============================================================
//                      线程(Threads)
// ============================================================
// Rust 的并发模型基于操作系统线程(1:1 模型)
// 所有权和类型系统在编译时就能防止数据竞争
// 【口号】"无畏并发"(Fearless Concurrency)
//
// 关键概念:
// - Send trait: 类型可以安全地在线程间转移所有权
// - Sync trait: 类型可以安全地在线程间共享引用
// 大部分类型都自动实现了这两个 trait

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

fn main() {
    println!("=== 线程 ===");

    // ----------------------------------------------------------
    // 1. 创建线程
    // ----------------------------------------------------------
    // thread::spawn 创建新线程,接受一个闭包
    // 返回 JoinHandle,可以等待线程结束

    let handle = thread::spawn(|| {
        for i in 1..=5 {
            println!("子线程: {}", i);
            thread::sleep(Duration::from_millis(10));
        }
    });

    for i in 1..=3 {
        println!("主线程: {}", i);
        thread::sleep(Duration::from_millis(10));
    }

    // join() 等待线程完成
    // 【重要】如果不 join,主线程结束时子线程会被终止
    handle.join().unwrap();
    println!("所有线程完成\n");

    // ----------------------------------------------------------
    // 2. move 闭包(转移所有权到线程)
    // ----------------------------------------------------------
    // 线程可能比创建它的作用域活得更久
    // 所以必须用 move 获取数据的所有权

    let data = vec![1, 2, 3];
    let handle = thread::spawn(move || {
        // data 的所有权被移入线程
        println!("线程中的数据: {:?}", data);
    });
    // println!("{:?}", data);  // 错误!data 已被移动
    handle.join().unwrap();

    // ----------------------------------------------------------
    // 3. 返回值
    // ----------------------------------------------------------
    let handle = thread::spawn(|| {
        let mut sum = 0;
        for i in 1..=100 {
            sum += i;
        }
        sum  // 返回值
    });

    let result = handle.join().unwrap();
    println!("1 到 100 的和: {}\n", result);

    // ----------------------------------------------------------
    // 4. Mutex<T>(互斥锁)
    // ----------------------------------------------------------
    // Mutex 提供内部可变性,同一时刻只有一个线程能访问数据
    // lock() 返回 MutexGuard,离开作用域时自动解锁
    // 【注意】Mutex 在单线程中用 lock().unwrap() 即可
    //        在多线程中需要配合 Arc 使用

    println!("=== Mutex ===");

    let counter = Mutex::new(0);
    {
        let mut num = counter.lock().unwrap();
        *num += 1;
    } // MutexGuard 在此释放,锁被自动解开
    println!("单线程 Mutex: {}", *counter.lock().unwrap());

    // ----------------------------------------------------------
    // 5. Arc<T> + Mutex<T>(多线程共享数据)
    // ----------------------------------------------------------
    // Arc = Atomic Reference Counting(原子引用计数)
    // 【为什么不用 Rc】Rc 不是线程安全的,Arc 是
    // 【模式】Arc<Mutex<T>> 是多线程共享可变数据的标准模式

    println!("\n=== Arc + Mutex ===");

    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);  // 克隆 Arc(增加引用计数)
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

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

    println!("最终计数: {}", *counter.lock().unwrap()); // 10

    // ----------------------------------------------------------
    // 6. RwLock<T>(读写锁)
    // ----------------------------------------------------------
    // 允许多个读者或一个写者(与借用规则类似)
    // 【适用场景】读多写少的情况,比 Mutex 性能更好

    println!("\n=== RwLock ===");

    let data = Arc::new(RwLock::new(vec![1, 2, 3]));
    let mut handles = vec![];

    // 多个读者
    for i in 0..3 {
        let data = Arc::clone(&data);
        let handle = thread::spawn(move || {
            let read_guard = data.read().unwrap();
            println!("读者 {}: {:?}", i, *read_guard);
        });
        handles.push(handle);
    }

    // 一个写者
    {
        let data = Arc::clone(&data);
        let handle = thread::spawn(move || {
            let mut write_guard = data.write().unwrap();
            write_guard.push(4);
            println!("写者: 添加了 4");
        });
        handles.push(handle);
    }

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

    println!("最终数据: {:?}", *data.read().unwrap());

    // ----------------------------------------------------------
    // 7. 线程局部存储
    // ----------------------------------------------------------
    println!("\n=== 线程局部存储 ===");

    thread_local! {
        static COUNTER: std::cell::RefCell<u32> = std::cell::RefCell::new(0);
    }

    let mut handles = vec![];
    for id in 0..3 {
        let handle = thread::spawn(move || {
            COUNTER.with(|c| {
                *c.borrow_mut() += 1;
                println!("线程 {}: 局部计数 = {}", id, c.borrow());
            });
        });
        handles.push(handle);
    }

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

    // 主线程的计数器是独立的
    COUNTER.with(|c| {
        println!("主线程: 局部计数 = {}", c.borrow()); // 0
    });

    // ----------------------------------------------------------
    // 8. 实用示例:并行计算
    // ----------------------------------------------------------
    println!("\n=== 并行计算 ===");

    let data: Vec<u64> = (1..=1_000_000).collect();

    // 分块并行求和
    let num_threads = 4;
    let chunk_size = data.len() / num_threads;
    let data = Arc::new(data);
    let mut handles = vec![];

    for i in 0..num_threads {
        let data = Arc::clone(&data);
        let handle = thread::spawn(move || {
            let start = i * chunk_size;
            let end = if i == num_threads - 1 {
                data.len()
            } else {
                (i + 1) * chunk_size
            };
            let partial_sum: u64 = data[start..end].iter().sum();
            println!("线程 {}: 部分和 = {}", i, partial_sum);
            partial_sum
        });
        handles.push(handle);
    }

    let total: u64 = handles.into_iter().map(|h| h.join().unwrap()).sum();
    println!("总和: {}", total);
    println!("验证: {}", (1u64..=1_000_000).sum::<u64>());

    println!("\n=== 线程结束 ===");
}

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布