Rust

2025年08月22日更新 8 人订阅
原价: ¥ 6 限时优惠
专栏简介 Rust编程语言之错误处理 Rust 语言之 flod Rust编程语言之Cargo、Crates.io详解 Rust编程语言之枚举与模式匹配 Rust语言 - 接口设计的建议之受约束(Constrained) Rust编程语言之无畏并发 Rust语言 - 接口设计的建议之灵活(flexible) Rust语言 - 接口设计的建议之显而易见(Obvious) Rust语言 - 接口设计的建议之不意外(unsurprising) Rust 实战:构建实用的 CLI 工具 HTTPie Rust编程语言学习之高级特性 Rust内存管理揭秘:深度剖析指针与智能指针 解决Rust中数组和切片的编译时大小问题 《Rust编程之道》学习笔记一 Rust Async 异步编程 简易教程 使用 Async Rust 构建简单的 P2P 节点 Rust编程语言入门之模式匹配 Rust async 编程 Rust编程语言之编写自动化测试 Rust编程语言之函数式语言特性:迭代器和闭包 《Rust编程之道》学习笔记二 Rust Tips 比较数值 使用 Rust 开发一个微型游戏 Rust编程初探:深入理解Struct结构体 深入理解Rust中的内存管理:栈、堆与静态内存详解 深入理解 Rust 结构体:经典结构体、元组结构体和单元结构体的实现 深入掌握 Rust 结构体:从模板到实例化的完整指南 深入理解Rust中的结构体:逻辑与数据结合的实战示例 深入理解 Rust 枚举:从基础到实践 掌握Rust字符串的精髓:String与&str的最佳实践 全面解析 Rust 模块系统:实战案例与应用技巧 Rust 中的 HashMap 实战指南:理解与优化技巧 掌握Rust模式匹配:从基础语法到实际应用 Rust 中的面向对象编程:特性与实现指南 深入理解 Rust 的 Pin 和 Unpin:理论与实践解析 Rust Trait 与 Go Interface:从设计到实战的深度对比 从零开始:用 Rust 和 Axum 打造高效 Web 应用 Rust 错误处理详解:掌握 anyhow、thiserror 和 snafu Rust 如何优雅实现冒泡排序 链表倒数 K 节点怎么删?Python/Go/Rust 实战 用 Rust 玩转数据存储:JSON 文件持久化实战 Rust实战:打造高效字符串分割函数 如何高效学习一门技术:从知到行的飞轮效应 Rust 编程入门:Struct 让代码更优雅 Rust 编程:零基础入门高性能开发 用 Rust 写个猜数游戏,编程小白也能上手! Rust 入门教程:变量到数据类型,轻松掌握! 深入浅出 Rust:函数、控制流与所有权核心特性解析 从零开始:用 Rust 和 Axum 打造高效 Web 服务 Rust 集合类型解析:Vector、String、HashMap 深入浅出Rust:泛型、Trait与生命周期的硬核指南 Rust实战:博物馆门票限流系统设计与实现 用 Rust 打造高性能图片处理服务器:从零开始实现类似 Thumbor 的功能 Rust 编程入门实战:从零开始抓取网页并转换为 Markdown 深入浅出 Rust:高效处理二进制数据的 Bytes 与 BytesMut 实战 Rust智能指针:解锁内存管理的进阶之道 用 Rust 打造命令行利器:从零到一实现 mini-grep 解锁Rust代码组织:轻松掌握Package、Crate与Module Rust 所有权:从内存管理到生产力释放 深入解析 Rust 的面向对象编程:特性、实现与设计模式 Rust + Protobuf:从零打造高效键值存储项目 bacon 点燃 Rust:比 cargo-watch 更爽的开发体验 用 Rust 打造微型游戏:从零开始的 Flappy Dragon 开发之旅 函数式编程的Rust之旅:闭包与迭代器的深入解析与实践 探索Rust编程之道:从设计哲学到内存安全的学习笔记 精读《Rust编程之道》:吃透语言精要,彻底搞懂所有权与借用 Rust 避坑指南:搞定数值比较,别再让 0.1 + 0.2 != 0.3 困扰你! 告别 Vec!掌握 Rust bytes 库,解锁零拷贝的真正威力 告别竞态条件:基于 Axum 和 Serde 的 Rust 并发状态管理最佳实践 Rust 异步编程实践:从 Tokio 基础到阻塞任务处理模式 Rust 网络编程实战:用 Tokio 手写一个迷你 TCP 反向代理 (minginx) 保姆级教程:Zsh + Oh My Zsh 终极配置,让你的 Ubuntu 终端效率倍增 不止于后端:Rust 在 Web 开发中的崛起之路 (2024数据解读) Rust核心利器:枚举(Enum)与模式匹配(Match),告别空指针,写出优雅健壮的代码 Rust 错误处理终极指南:从 panic! 到 Result 的优雅之道 想用 Rust 开发游戏?这份超详细的入门教程请收好! 用 Rust 实现 HTTPie:一个现代 CLI 工具的构建过程 Rust 异步实战:从0到1,用 Tokio 打造一个高性能并发聊天室 深入 Rust 核心:彻底搞懂指针、引用与智能指针 Rust 生产级后端实战:用 Axum + sqlx 打造高性能短链接服务 深入 Rust 内存模型:栈、堆、所有权与底层原理 Rust 核心概念解析:引用、借用与内部可变性 掌握 Rust 核心:生命周期与借用检查全解析 Rust 内存布局深度解析:从对齐、填充到 repr 属性 Rust Trait 分派机制:静态与动态的抉择与权衡 Rust Thread::Builder 用法详解:线程命名与栈大小设置 Rust 泛型 Trait:关联类型与泛型参数的核心区别 Rust Scoped Threads 实战:更安全、更简洁的并发编程 Rust 核心设计:孤儿规则与代码一致性解析 Rust 实战:从零构建一个多线程 Web 服务器 Rust Web 开发实战:构建教师管理 API 硬核实战:从零到一,用 Rust 和 Axum 构建高性能聊天服务后端 Rust Web 开发实战:使用 SQLx 连接 PostgreSQL 数据库 硬核入门:从零开始,用 Actix Web 构建你的第一个 Rust REST API (推荐 🔥) Rust 并发编程:详解线程间数据共享的几种核心方法 Rust并发安全基石:Mutex与RwLock深度解析

Rust并发安全基石:Mutex与RwLock深度解析

Rust并发安全基石:Mutex与RwLock深度解析在多线程编程中,如何安全、高效地共享和修改数据是一个永恒的核心难题。Rust通过其严格的所有权和借用检查机制,在编译期就为我们杜绝了大量数据竞争问题。但当多个线程确实需要访问同一份数据时,我们就必须借助强大的同步原语(Synchronizati

Rust并发安全基石:Mutex与RwLock深度解析

在多线程编程中,如何安全、高效地共享和修改数据是一个永恒的核心难题。Rust通过其严格的所有权和借用检查机制,在编译期就为我们杜绝了大量数据竞争问题。但当多个线程确实需要访问同一份数据时,我们就必须借助强大的同步原语(Synchronization Primitives)。

Mutex(互斥锁)和RwLock(读写锁)正是Rust标准库为此提供的两大并发安全基石。本文将通过详尽的原理讲解和可运行的代码实例,带你深入探索这两者的工作机制、核心区别、适用场景,并揭示其独特的“锁中毒”(Lock Poisoning)安全策略。在此之前,我们也会先回顾单线程环境下的内部可变性工具CellRefCell,为彻底理解并发安全打下坚实的基础。

本文内容

  • Cell<T>
  • RefCell<T>
  • Mutex
  • RwLock

Cell<T>

Cell<T>RefCell<T> 都实现了内部可变性模式。

内部可变性:通过不可变引用来修改其持有的值。

对于一个对象 T,只能存在以下两种情况之一:

  1. 若干个指向该对象的不可变引用 (&T)
  2. 一个指向该对象的可变引用 (&mut T)

Cell 只能用于单线程

  • 通过移动(move) 值的方式实现内部可变性
  • 无法获取到内部值的 &mut T
  • 无法直接获取内部的值,除非用别的值替换它
  • 确保不会有多个引用同时指向内部的值
  • 针对实现了 Copy 的类型,get 方法可通过复制的方式获取内部值
  • 针对实现了Default的类型,take 方法会将当前内部值替换为 Default::default(),并返回原来的值
  • 针对所有类型
    • Replace 方法,替换当前内部值,返回原来的内部值
    • into_inner 方法,消耗 (consume) 掉这个 Cell<T>,并返回内部值
    • set 方法,替换当前的内部值,丢弃原来的值
  • Cell<T> 一般用于简单类型(如数值),因为复制/移动不会太消耗资源,它无法获取内部类型的直接引用
  • 在可能得情况下应该优先使用Cell<T> 而不是其它的 Cell 类型
  • 对于较大的或者不可复制 (non-copy) 的类型,RefCell 更有优势

Cell<T>实操

use std::cell::Cell;

fn main() {
    let cell = Cell::new(5);
    assert_eq!(cell.get(), 5);

    assert_eq!(cell.replace(10), 5);
    assert_eq!(cell.get(), 10);

    let ten = cell.into_inner();
    assert_eq!(ten, 10);

    let cell = Cell::new(String::from("hello"));
    assert_eq!(cell.take(), "hello");
    assert_eq!(cell.take(), String::default());

    cell.set(String::from("world"));
    assert_eq!(cell.take(), "world");
}

运行

RustJourney/cell on  main [?] is 📦 0.1.0 via 🦀 1.89.0 
➜ cargo run
   Compiling cell v0.1.0 (/Users/qiaopengjun/Code/Rust/RustJourney/cell)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.28s
     Running `target/debug/cell`

RefCell<T>

  • Cell<T> 不同,RefCell<T> 允许直接借用它的内部值,但是会有一点运行时开销
  • RefCell<T> 不仅持有 T 的值,还持有一个计数器,用来追踪有多少个借用
    • 借用是在运行时被追踪的
    • Rust 的原生引用类型在编译时进行静态检查
  • borrow():可以获取对 RefCell 内部值的不可变引用 (&T)
  • borrow_mut():可以获取对 RefCell 内部值的可变引用 (&mut T)
  • 其它:try_borrow()try_borrow_mut()into_inner()replace()take()...
  • 借用规则:
    • 任意数量的不可变借用 (&T)
    • 或单个可变借用 (&mut T)
    • 如果违反规则则线程会 panic
  • 在同一作用域内,一个值要么可以有多个不可变借用(&T),要么只能有一个可变借用(&mut T)。

RefCell<T> 实操

use std::cell::RefCell;

fn main() {
    let rc = RefCell::new(5);
    println!("rc = {rc:#?}");

    {
        let five = rc.borrow();
        let five1 = rc.borrow();
        assert_eq!(*five, 5);
        assert_eq!(*five1, 5);
    }

    let mut f = rc.borrow_mut();
    *f += 10;
    assert_eq!(*f, 15);
    println!("f = {f:#?}");

    let v = rc.try_borrow();
    assert!(v.is_err());

    drop(f);

    // RefMut 实现了 Deref Trait
    *rc.borrow_mut() += 10;

    println!("rc = {rc:#?}");
}

运行

RustJourney/cell on  main [?] is 📦 0.1.0 via 🦀 1.89.0 
➜ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/cell`
rc = RefCell {
    value: 5,
}
f = 15
rc = RefCell {
    value: 25,
}

Mutex

Mutual Exclusion

互斥锁:一种用于保护共享数据的互斥原语。

  • 原语 (primitive):最基本、不可再分解的操作或机制
  • Mutex
    • 最常见的用于在线程间分享(可变)数据的工具
    • 只允许对数据的独占 (exclusive) 访问,临时阻塞同一时刻想要访问数据的其它线程

Mutex两种状态 (LOCKED UNLOCKED)

  • 访问数据前需要请求锁 (lock)

  • 处理完成时需要移除锁 (unlock)

  • 锁定 (locked)

  • 未锁定 (unlocked)

  • Mutex 锁定 Lock

  • Mutex 解锁 unlock

  • 这里的 unlock 是指等着 MutexGuard 走出作用域

  • 解锁的线程与锁定的线程应该是同一个

...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论