Rust并发安全基石:Mutex与RwLock深度解析在多线程编程中,如何安全、高效地共享和修改数据是一个永恒的核心难题。Rust通过其严格的所有权和借用检查机制,在编译期就为我们杜绝了大量数据竞争问题。但当多个线程确实需要访问同一份数据时,我们就必须借助强大的同步原语(Synchronizati
在多线程编程中,如何安全、高效地共享和修改数据是一个永恒的核心难题。Rust通过其严格的所有权和借用检查机制,在编译期就为我们杜绝了大量数据竞争问题。但当多个线程确实需要访问同一份数据时,我们就必须借助强大的同步原语(Synchronization Primitives)。
Mutex
(互斥锁)和RwLock
(读写锁)正是Rust标准库为此提供的两大并发安全基石。本文将通过详尽的原理讲解和可运行的代码实例,带你深入探索这两者的工作机制、核心区别、适用场景,并揭示其独特的“锁中毒”(Lock Poisoning)安全策略。在此之前,我们也会先回顾单线程环境下的内部可变性工具Cell
与RefCell
,为彻底理解并发安全打下坚实的基础。
Cell<T>
RefCell<T>
Mutex
RwLock
Cell<T>
Cell<T>
和 RefCell<T>
都实现了内部可变性模式。
内部可变性:通过不可变引用来修改其持有的值。
对于一个对象 T,只能存在以下两种情况之一:
&T
)&mut T
)Cell 只能用于单线程
&mut T
Copy
的类型,get
方法可通过复制的方式获取内部值Default
的类型,take
方法会将当前内部值替换为 Default::default()
,并返回原来的值Cell<T>
,并返回内部值Cell<T>
一般用于简单类型(如数值),因为复制/移动不会太消耗资源,它无法获取内部类型的直接引用Cell<T>
而不是其它的 Cell 类型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 的值,还持有一个计数器,用来追踪有多少个借用
borrow()
:可以获取对 RefCell
内部值的不可变引用 (&T
)borrow_mut()
:可以获取对 RefCell
内部值的可变引用 (&mut T
)try_borrow()
、try_borrow_mut()
、into_inner()
、replace()
、take()
...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
互斥锁:一种用于保护共享数据的互斥原语。
Mutex
:
Mutex
两种状态 (LOCKED UNLOCKED)访问数据前需要请求锁 (lock)
处理完成时需要移除锁 (unlock)
锁定 (locked)
未锁定 (unlocked)
Mutex
锁定 Lock
Mutex
解锁 unlock
这里的 unlock 是指等着 MutexGuard
走出作用域
解锁的线程与锁定的线程应该是同一个
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!