4 个版本
0.2.0 | 2023 年 12 月 16 日 |
---|---|
0.1.2 | 2023 年 12 月 16 日 |
0.1.1 | 2023 年 12 月 6 日 |
0.1.0 | 2023 年 12 月 4 日 |
422 在 内存管理 中
每月下载 48 次
9KB
112 行
此 crate 提供了一个通用引用计数锁的特质,具有内部可变性,允许多个读者或单个写入者,可以代表 Rc<RefCell<T>>
或 Arc<RwLock<T>>
。
lib.rs
:
一个通用引用计数锁的特质,具有内部可变性,允许多个读者或单个写入者,可以代表 Rc<RefCell<T>>
或 Arc<RwLock<T>>
。
基础
动机
Rc<RefCell<T>>
和 Arc<RwLock<T>>
分别是 Rust 在单线程和多线程场景下表示内部可变性的习惯用法。这两种类型都为它们管理的数据提供了多读者或单写入者的基本接口。
然而,尽管它们相似,这些类型没有共享任何公共特质,因此不能以通用方式使用:不能定义一个可以接受 Rc<RefCell<T>>
或 Arc<RwLock<T>>
的函数参数或结构字段。如果事先不知道将传递哪种智能指针(Rc 或 Arc),这会导致代码重复。
UniRcLock
通过为Rc<RefCell<T>>
和Arc<RwLock<T>>
提供公共特性,使得它们可以在单线程和多线程场景中以通用方式使用,从而解决了这个问题。
性能
UniRcLock
是一个零成本抽象。
限制
使用UniRcLock
时,在RwLock<T>
中恢复锁定中毒的能力将丢失。当锁定中毒时,方法read()
和write()
将引发panic。
示例
一个接受Rc<RefCell<T>>
和Arc<RwLock<T>>
的泛型函数
#
#[derive(Debug)]
struct Foo(i32);
fn incr_foo(v: impl UniRcLock<Foo>){
v.write().0 += 1;
}
// Using Rc
let ptr1 = Rc::new(RefCell::new(Foo(0)));
incr_foo(ptr1.clone());
println!("After increment: {:?}", ptr1);
// Using Arc
let ptr2 = Arc::new(RwLock::new(Foo(0)));
incr_foo(ptr2.clone());
println!("After increment: {:?}", ptr2);
泛型结构的示例,它可以持有Rc<RefCell<T>>
或Arc<RwLock<T>>
#
// A user struct
struct State {val: i32}
// Generic wrapper
#[derive(Debug,Clone)]
struct StateHandler<T: UniRcLock<State>> {
state: T,
}
impl<T: UniRcLock<State>> StateHandler<T> {
// Constructor taking either Rc<RefCell<T>>` or `Arc<RwLock<T>>
fn new(val: T) -> Self {
Self{state: val}
}
}
// Using with Rc
{
let st = Rc::new(RefCell::new(State { val: 42 }));
let st_handler = StateHandler::new(st);
st_handler.state.write().val += 1;
println!("{}", st_handler.state.read().val);
}
// Using with Arc in exactly the same way
{
let st = Arc::new(RwLock::new(State { val: 42 }));
let st_handler = StateHandler::new(st);
st_handler.state.write().val += 1;
println!("{}", st_handler.state.read().val);
}
// Using in multiple threads with Arc
{
let st = Arc::new(RwLock::new(State { val: 42 }));
let st_handler = StateHandler::new(st);
let threads: Vec<_> = (0..10)
.map(|i| {
let h = st_handler.clone();
thread::spawn(move || {
h.state.write().val += 1;
println!("Thread #{i} incremented");
})
})
.collect();
for t in threads {
t.join().unwrap();
}
println!("Result: {}", st_handler.state.read().val);
}
预期地,此示例无法与Rc
编译,因为它没有实现Send
。