本文简要介绍rust语言中 Struct std::sync::Arc
的用法。
用法
pub struct Arc<T> where T: ?Sized, { /* fields omitted */ }
线程安全的引用计数指针。 'Arc' 代表“原子引用计数”。
Arc<T>
类型提供在堆中分配的类型为 T
的值的共享所有权。在 Arc
上调用 clone
会生成一个新的 Arc
实例,该实例指向堆上与源 Arc
相同的分配,同时增加引用计数。当指向给定分配的最后一个Arc
指针被销毁时,存储在该分配中的值(通常称为“inner value”)也将被删除。
Rust 中的共享引用默认不允许突变,Arc
也不异常:您通常无法获取对 Arc
内部某些内容的可变引用。如果您需要通过 Arc
进行变异,请使用 Mutex
、 RwLock
或 Atomic
类型之一。
线程安全
与 Rc<T>
不同,Arc<T>
使用原子操作进行引用计数。这意味着它是线程安全的。缺点是原子操作比普通的内存访问更昂贵。如果您不在线程之间共享reference-counted 分配,请考虑使用 Rc<T>
来降低开销。 Rc<T>
是一个安全的默认值,因为编译器将捕获任何在线程之间发送 Rc<T>
的尝试。但是,库可能会选择Arc<T>
,以便为库使用者提供更大的灵活性。
只要 T
实现 Send
和 Sync
,Arc<T>
就会实现 Send
和 Sync
。为什么不能将非线程安全类型 T
放入 Arc<T>
中以使其成为线程安全?乍一看这可能有点counter-intuitive:毕竟,Arc<T>
线程安全的重点不是吗?关键是:Arc<T>
使得对同一数据具有多个所有权是线程安全的,但它并没有为其数据添加线程安全性。考虑Arc<RefCell<T>>
。 RefCell<T>
不是 Sync
,如果 Arc<T>
始终是 Send
,则 Arc<RefCell<T>>
也是如此。但这样我们就会遇到一个问题: RefCell<T>
不是线程安全的;它使用非原子操作跟踪借用计数。
最后,这意味着您可能需要将 Arc<T>
与某种 std::sync
类型配对,通常是 Mutex<T>
。
使用Weak
中断循环
std::sync::Arc.downgrade方法可用于创建非拥有Weak
指针。 AWeak
指针可以是std::sync::Weak.upgraded 至Arc
,但这会返回None
如果存储在分配中的值已被删除。换句话说,Weak
指针不会使分配内的值保持活动状态;然而,他们做保持分配(值的后备存储)处于活动状态。
Arc
指针之间的循环永远不会被释放。因此, Weak
用于中断循环。例如,一棵树可能具有从父节点到子节点的强 Arc
指针,以及从子节点返回到父节点的 Weak
指针。
克隆参考
使用为 Arc<T>
和 Weak<T>
实现的 Clone
特征从现有的 reference-counted 指针创建新引用。
use std::sync::Arc;
let foo = Arc::new(vec![1.0, 2.0, 3.0]);
// The two syntaxes below are equivalent.
let a = foo.clone();
let b = Arc::clone(&foo);
// a, b, and foo are all Arcs that point to the same memory location
Deref
行为
Arc<T>
自动取消引用 T
(通过 Deref
特征),因此您可以对 Arc<T>
类型的值调用 T
的方法。为了避免与 T
的方法发生名称冲突,Arc<T>
本身的方法是关联函数,使用 fully qualified syntax 进行调用:
use std::sync::Arc;
let my_arc = Arc::new(());
let my_weak = Arc::downgrade(&my_arc);
Arc<T>
对 Clone
等特征的实现也可以使用完全限定的语法来调用。有些人喜欢使用完全限定的语法,而另一些人则喜欢使用method-call 语法。
use std::sync::Arc;
let arc = Arc::new(());
// Method-call syntax
let arc2 = arc.clone();
// Fully qualified syntax
let arc3 = Arc::clone(&arc);
Weak<T>
不会自动取消对 T
的引用,因为内部值可能已被删除。
例子
在线程之间共享一些不可变的数据:
use std::sync::Arc;
use std::thread;
let five = Arc::new(5);
for _ in 0..10 {
let five = Arc::clone(&five);
thread::spawn(move || {
println!("{:?}", five);
});
}
共享一个可变的 AtomicUsize
:
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
let val = Arc::new(AtomicUsize::new(5));
for _ in 0..10 {
let val = Arc::clone(&val);
thread::spawn(move || {
let v = val.fetch_add(1, Ordering::SeqCst);
println!("{:?}", v);
});
}
有关一般引用计数的更多示例,请参阅 rc 文档。
相关用法
- Rust Arc.assume_init用法及代码示例
- Rust Arc.make_mut用法及代码示例
- Rust Arc.try_new用法及代码示例
- Rust Arc.increment_strong_count用法及代码示例
- Rust Arc.decrement_strong_count用法及代码示例
- Rust Arc.try_new_zeroed用法及代码示例
- Rust Arc.new_uninit_slice用法及代码示例
- Rust Arc.strong_count用法及代码示例
- Rust Arc.downcast用法及代码示例
- Rust Arc.try_unwrap用法及代码示例
- Rust Arc.get_mut_unchecked用法及代码示例
- Rust Arc.get_mut用法及代码示例
- Rust Arc.from_raw用法及代码示例
- Rust Arc用法及代码示例
- Rust Arc.ptr_eq用法及代码示例
- Rust Arc.new用法及代码示例
- Rust Arc.weak_count用法及代码示例
- Rust Arc.new_cyclic用法及代码示例
- Rust Arc.new_zeroed用法及代码示例
- Rust Arc.into_raw用法及代码示例
- Rust Arc.as_ptr用法及代码示例
- Rust Arc.new_zeroed_slice用法及代码示例
- Rust Arc.downgrade用法及代码示例
- Rust Arc.try_new_uninit用法及代码示例
- Rust Arc.new_uninit用法及代码示例
注:本文由纯净天空筛选整理自rust-lang.org大神的英文原创作品 Struct std::sync::Arc。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。