系统编程

第19课:通道与互斥

🎯 本课目标

掌握mpsc通道、Mutex、RwLock等线程同步原语。

1. mpsc通道

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

fn main() {
    let (tx, rx) = msc::channel();

    thread::spawn(move || {
        let vals = vec![
            String::from("hi"),
            String::from("from"),
            String::from("thread"),
        ];
        for val in vals {
            tx.send(val).unwrap();
        }
    });

    for received in rx {
        println!("收到: {}", received);
    }
}

✅ 编译验证通过

2. 多生产者

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

fn main() {
    let (tx, rx) = msc::channel();
    let tx1 = tx.clone();

    thread::spawn(move || {
        let vals = vec![String::from("A1"), String::from("A2")];
        for v in vals { tx1.send(v).unwrap(); }
    });

    thread::spawn(move || {
        let vals = vec![String::from("B1"), String::from("B2")];
        for v in vals { tx.send(v).unwrap(); }
    });

    for received in rx {
        println!("收到: {}", received);
    }
}

✅ 编译验证通过

3. Mutex互斥锁

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

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

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        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());
}

✅ 编译验证通过

4. RwLock读写锁

use std::sync::{Arc, RwLock};

fn main() {
    let data = Arc::new(RwLock::new(vec![1, 2, 3]));

    // 多个读者可同时持有
    let r1 = data.read().unwrap();
    let r2 = data.read().unwrap();  // ✅ 同时读
    println!("r1={:?} r2={:?}", *r1, *r2);
    drop(r1); drop(r2);

    // 写需要独占
    let mut w = data.write().unwrap();
    w.push(4);
}

✅ 编译验证通过

5. 同步原语对比

原语场景特点
Mutex互斥访问同一时刻一个线程
RwLock读多写少多读者或单写者
mpsc消息传递生产者-消费者
Atomic简单计数无锁,高性能
Barrier同步点等待所有线程到达
Condvar条件等待等待条件满足
Mutex内存模型: ┌──────────────┐ │ Mutex │ │ ┌──────────┐ │ │ │ lock_state│ │ ← 原子操作 │ └──────────┘ │ │ ┌──────────┐ │ │ │ data: 0 │ │ ← 受保护的数据 │ └──────────┘ │ └──────────────┘ 线程1: lock() → 获取锁 → 修改data → drop()释放 线程2: lock() → 等待... → 获取锁 → 修改 → 释放 Arc<Mutex<T>> = 共享所有权 + 互斥访问 这是Rust并发最常用的组合!

📝 练习题

练习1:生产者-消费者

用mpsc实现多生产者多消费者模式。

练习2:线程安全缓存

用Arc+RwLock+HashMap实现并发缓存。

练习3:哲学家就餐

用Mutex实现哲学家就餐问题的解决方案。

🏆

成就解锁:同步守护者

掌握线程同步——安全共享数据的艺术

🔬 深度理解:Rust与系统编程

系统编程的核心挑战是在不牺牲安全的前提下获得最大性能。Rust如何实现这个目标:

1. 无GC的内存管理

所有权系统在编译期确定每个值的生命周期,不需要运行时垃圾回收。这意味着:无停顿、可预测延迟、更少内存占用。

2. 零成本抽象到硬件

泛型单态化、内联、LLVM优化——高级代码编译为与手写C相当的机器码。

3. 并发无数据竞争

Send/Sync trait在编译期保证:如果是并发访问,要么只读,要么互斥。数据竞争不可能发生。

📊 Rust vs C/C++对比

特性RustCC++
内存安全✅ 编译期❌ 手动⚠️ 部分RAII
线程安全✅ 编译期
无GC
零成本抽象⚠️ 宏✅ 模板
包管理✅ Cargo⚠️ vcpkg
学习曲线陡峭中等极陡

🛡️ 安全编码实践

即使Rust保证内存安全和线程安全,仍需注意:

Rust系统编程课程 · 第19课 · 2026

📚 扩展阅读

以下资源帮助你深入学习本课主题:

  • The Rust Programming Language — 官方教程,Rust圣经
  • Rust by Example — 通过示例学习Rust
  • Rust Reference — 语言参考手册
  • Rustnomicon — Unsafe Rust黑魔法指南
  • Too Many Lists — 用Rust实现各种链表

🔑 关键术语回顾

本课涉及的核心概念,确保你理解每一个:

术语说明
所有权Rust内存管理的核心机制,每个值有唯一所有者
借用通过引用访问数据,不获取所有权
生命周期引用有效的范围,编译期分析工具
traitRust的接口/抽象机制,类似其他语言的接口
泛型参数化类型,零成本抽象
模式匹配强大的数据解构和分支机制
零成本抽象高层抽象不引入运行时开销
fearless concurrency编译器保证线程安全

💬 学习建议

  1. 动手编码 — 每个代码示例都在本地运行一遍
  2. 修改实验 — 故意改错代码,看编译器报什么错
  3. 完成练习 — 每课的练习题是巩固知识的关键
  4. 阅读源码 — 看标准库和优秀开源项目的实现
  5. 写项目 — 真正掌握需要构建真实项目

🤔 常见问题

Q: Rust学习曲线真的很陡吗?

A: 前期确实需要适应所有权和借用检查器,但一旦理解了,这些概念会让你的代码更可靠。大多数人2-4周就能上手。

Q: Rust适合什么项目?

A: 系统编程、Web服务、CLI工具、嵌入式、WASM、网络服务、数据库等。基本上需要性能和安全的地方都适合。

Q: 遇到编译错误怎么办?

A: Rust编译器的错误信息非常友好!仔细阅读,通常会指出问题所在和修复建议。也可以用cargo clippy获取更多提示。