Struct std::sync::Arc 1.0.0[−][src]
pub struct Arc<T> where
T: ?Sized, { /* fields omitted */ }
Expand description
线程安全的引用计数指针。Arc
代表原子引用计数。
Arc<T>
类型提供了在堆中分配的 T
类型值的共享所有权。在 Arc
上调用 clone
会生成一个新的 Arc
实例,该实例指向堆上与源 Arc
相同的分配,同时增加了引用计数。
当指向给定分配的最后一个 Arc
指针被销毁时,存储在该分配中的值 (通常称为 “内部值”) 也将被丢弃。
默认情况下,Rust 中的共享引用不允许可变的,Arc
也不例外:您通常无法获得 Arc
内部内容的可变引用。如果需要通过 Arc
进行可变的,请使用 Mutex
,RwLock
或 Atomic
类型之一。
线程安全
与 Rc<T>
不同,Arc<T>
使用原子操作进行引用计数。这意味着它是线程安全的。缺点是原子操作比普通的内存访问更昂贵。如果您不共享线程之间的引用计数分配,请考虑使用 Rc<T>
来降低开销。
Rc<T>
是一个安全的默认值,因为编译器会捕获在线程之间发送 Rc<T>
的任何尝试。
但是,一个库可能会选择 Arc<T>
,以便为库的消费者提供更大的灵活性。
只要 T
实现 Send
和 Sync
,Arc<T>
就会实现 Send
和 Sync
。
为什么不能在 Arc<T>
中放置非线程安全类型 T
使其成为线程安全的? 起初这可能有点违反直觉:毕竟,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
的中断循环
downgrade
方法可用于创建非所有者 Weak
指针。Weak
指针可以 upgrade
为 Arc
,但如果存储在分配中的值已经被丢弃,这将返回 None
。
换句话说,Weak
指针不会使分配内部的值保持活动状态。然而,它们确实使分配(值的后备存储)保持活动状态。
Arc
指针之间的循环将永远不会被释放。
因此,Weak
用于中断循环。例如,一棵树可能具有从父节点到子节点的强 Arc
指针,以及从子节点返回到其父节点的 Weak
指针。
克隆引用
使用为 Arc<T>
和 Weak<T>
实现的 Clone
trait 从现有的引用计数指针创建新的引用。
use std::sync::Arc;
let foo = Arc::new(vec![1.0, 2.0, 3.0]);
// 以下两种语法是等效的。
let a = foo.clone();
let b = Arc::clone(&foo);
// a、b 和 foo 都是指向同一内存位置的 Arc
RunDeref
行为
Arc<T>
自动取消对 T
的引用 (通过 Deref
trait),因此您可以在类型为 Arc<T>
的值上调用 T
的方法。为了避免与 T
的方法名称冲突,Arc<T>
本身的方法是关联函数,使用 完全限定语法 调用:
use std::sync::Arc;
let my_arc = Arc::new(());
let my_weak = Arc::downgrade(&my_arc);
RunArc<T>
也可以使用完全限定语法来调用诸如 Clone
之类的 traits 实现。
有些人喜欢使用完全限定的语法,而另一些人则喜欢使用方法调用语法。
use std::sync::Arc;
let arc = Arc::new(());
// 方法调用语法
let arc2 = arc.clone();
// 完全限定的语法
let arc3 = Arc::clone(&arc);
RunWeak<T>
不会自动解引用到 T
,因为内部值可能已经被丢弃了。
Examples
在线程之间共享一些不可变数据:
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);
});
}
Run共享可变的 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);
});
}
Run有关更多一般引用计数示例,请参见 rc
文档。
Implementations
创建一个具有未初始化内容的新 Arc
,并用 0
字节填充内存。
有关正确和不正确使用此方法的示例,请参见 MaybeUninit::zeroed
。
Examples
#![feature(new_uninit)]
use std::sync::Arc;
let zero = Arc::<u32>::new_zeroed();
let zero = unsafe { zero.assume_init() };
assert_eq!(*zero, 0)
Run创建一个新的 Pin<Arc<T>>
。
如果 T
未实现 Unpin
,则 data
将被固定在内存中并且无法移动。
创建一个新的 Pin<Arc<T>>
,如果分配失败则返回错误。
构造具有未初始化内容的新 Arc
,如果分配失败,则返回错误。
Examples
#![feature(new_uninit, allocator_api)]
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let mut five = Arc::<u32>::try_new_uninit()?;
let five = unsafe {
// 延迟初始化:
Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
five.assume_init()
};
assert_eq!(*five, 5);
Run创建一个具有未初始化内容的新 Arc
,并用 0
字节填充内存,如果分配失败,则返回错误。
有关正确和不正确使用此方法的示例,请参见 MaybeUninit::zeroed
。
Examples
#![feature(new_uninit, allocator_api)]
use std::sync::Arc;
let zero = Arc::<u32>::try_new_zeroed()?;
let zero = unsafe { zero.assume_init() };
assert_eq!(*zero, 0);
Run创建一个具有未初始化内容的新原子引用计数切片。
Examples
#![feature(new_uninit)]
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let mut values = Arc::<[u32]>::new_uninit_slice(3);
let values = unsafe {
// 延迟初始化:
Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
values.assume_init()
};
assert_eq!(*values, [1, 2, 3])
Run创建一个具有未初始化内容的新原子引用计数切片,内存中填充 0
字节。
有关正确和不正确使用此方法的示例,请参见 MaybeUninit::zeroed
。
Examples
#![feature(new_uninit)]
use std::sync::Arc;
let values = Arc::<[u32]>::new_zeroed_slice(3);
let values = unsafe { values.assume_init() };
assert_eq!(*values, [0, 0, 0])
Run转换为 Arc<T>
。
Safety
与 MaybeUninit::assume_init
一样,由调用者负责确保内部值确实处于初始化状态。
在内容尚未完全初始化时调用此方法会立即导致未定义的行为。
Examples
#![feature(new_uninit)]
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let mut five = Arc::<u32>::new_uninit();
let five = unsafe {
// 延迟初始化:
Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
five.assume_init()
};
assert_eq!(*five, 5)
Run转换为 Arc<[T]>
。
Safety
与 MaybeUninit::assume_init
一样,由调用者负责确保内部值确实处于初始化状态。
在内容尚未完全初始化时调用此方法会立即导致未定义的行为。
Examples
#![feature(new_uninit)]
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let mut values = Arc::<[u32]>::new_uninit_slice(3);
let values = unsafe {
// 延迟初始化:
Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
values.assume_init()
};
assert_eq!(*values, [1, 2, 3])
Run消耗 Arc
,返回包装的指针。
为避免内存泄漏,必须使用 Arc::from_raw
将指针转换回 Arc
。
Examples
use std::sync::Arc;
let x = Arc::new("hello".to_owned());
let x_ptr = Arc::into_raw(x);
assert_eq!(unsafe { &*x_ptr }, "hello");
Run从裸指针构造 Arc<T>
。
裸指针必须事先由调用返回到 Arc<U>::into_raw
,其中 U
的大小和对齐方式必须与 T
相同。
如果 U
是 T
,这是很简单的。
请注意,如果 U
不是 T
,但是具有相同的大小和对齐方式,则基本上就像对不同类型的引用进行转换一样。
有关在这种情况下适用的限制的更多信息,请参见 mem::transmute
。
from_raw
的用户必须确保 T
的特定值仅被丢弃一次。
此函数不安全,因为使用不当可能会导致内存不安全,即使从未访问返回的 Arc<T>
也是如此。
Examples
use std::sync::Arc;
let x = Arc::new("hello".to_owned());
let x_ptr = Arc::into_raw(x);
unsafe {
// 转换回 `Arc` 以防止泄漏。
let x = Arc::from_raw(x_ptr);
assert_eq!(&*x, "hello");
// 进一步调用 `Arc::from_raw(x_ptr)` 将导致内存不安全。
}
// 当 `x` 超出上面的作用域时,其内存将被释放,所以 `x_ptr` 现在悬垂了!
Run与提供的指针关联的 Arc<T>
上的强引用计数加 1。
Safety
指针必须已经通过 Arc::into_raw
获得,并且关联的 Arc
实例必须有效 (即
在此方法的持续时间内,强引用计数必须至少为 1)。
Examples
use std::sync::Arc;
let five = Arc::new(5);
unsafe {
let ptr = Arc::into_raw(five);
Arc::increment_strong_count(ptr);
// 此断言是确定性的,因为我们尚未在线程之间共享 `Arc`。
let five = Arc::from_raw(ptr);
assert_eq!(2, Arc::strong_count(&five));
}
Run将与提供的指针关联的 Arc<T>
上的强引用计数减 1。
Safety
指针必须已经通过 Arc::into_raw
获得,并且关联的 Arc
实例必须有效 (即
调用此方法时,强引用计数必须至少为 1)。
此方法可用于释放最终的 Arc
和后备存储,但不应在最终的 Arc
释放后调用。
Examples
use std::sync::Arc;
let five = Arc::new(5);
unsafe {
let ptr = Arc::into_raw(five);
Arc::increment_strong_count(ptr);
// 这些断言是确定性的,因为我们尚未在线程之间共享 `Arc`。
let five = Arc::from_raw(ptr);
assert_eq!(2, Arc::strong_count(&five));
Arc::decrement_strong_count(ptr);
assert_eq!(1, Arc::strong_count(&five));
}
Run对给定的 Arc
进行可变引用。
如果有其他 Arc
指针指向同一分配,则 make_mut
会将内部值 clone
到新分配以确保唯一的所有权。
这也称为写时克隆。
但是,如果没有其他指向此分配的 Arc
指针,而是一些 Weak
指针,则 Weak
指针将被解除关联,并且不会克隆内部值。
另请参见 get_mut
,它会失败而不是克隆内部值或取消关联 Weak
指针。
Examples
use std::sync::Arc;
let mut data = Arc::new(5);
*Arc::make_mut(&mut data) += 1; // 不会克隆任何东西
let mut other_data = Arc::clone(&data); // 不会克隆内部数据
*Arc::make_mut(&mut data) += 1; // 克隆内部数据
*Arc::make_mut(&mut data) += 1; // 不会克隆任何东西
*Arc::make_mut(&mut other_data) *= 2; // 不会克隆任何东西
// 现在,`data` 和 `other_data` 指向不同的分配。
assert_eq!(*data, 8);
assert_eq!(*other_data, 12);
RunWeak
指针将被解除关联:
use std::sync::Arc;
let mut data = Arc::new(75);
let weak = Arc::downgrade(&data);
assert!(75 == *data);
assert!(75 == *weak.upgrade().unwrap());
*Arc::make_mut(&mut data) += 1;
assert!(76 == *data);
assert!(weak.upgrade().is_none());
Run将变量引用返回给定的 Arc
,而不进行任何检查。
另请参见 get_mut
,它是安全的并且进行适当的检查。
Safety
在返回的借用期间,不得解引用其他指向相同分配的 Arc
或 Weak
指针。
如果不存在这样的指针 (例如紧接在 Arc::new
之后),则情况很简单。
Examples
#![feature(get_mut_unchecked)]
use std::sync::Arc;
let mut x = Arc::new(String::new());
unsafe {
Arc::get_mut_unchecked(&mut x).push_str("foo")
}
assert_eq!(*x, "foo");
Run尝试将 Arc<dyn Any + Send + Sync>
转换为具体类型。
Examples
use std::any::Any;
use std::sync::Arc;
fn print_if_string(value: Arc<dyn Any + Send + Sync>) {
if let Ok(string) = value.downcast::<String>() {
println!("String ({}): {}", string.len(), string);
}
}
let my_string = "Hello World".to_string();
print_if_string(Arc::new(my_string));
print_if_string(Arc::new(0i8));
RunTrait Implementations
use the Display impl or to_string()
replaced by Error::source, which can support downcasting
获取 Iterator
中的每个元素,并将其收集到 Arc<[T]>
中。
性能特点
一般情况
在一般情况下,首先要收集到 Vec<T>
中来收集到 Arc<[T]>
中。也就是说,编写以下内容时:
let evens: Arc<[u8]> = (0..10).filter(|&x| x % 2 == 0).collect();
Run这就像我们写的那样:
let evens: Arc<[u8]> = (0..10).filter(|&x| x % 2 == 0)
.collect::<Vec<_>>() // 第一组分配在此处发生。
.into(); // `Arc<[T]>` 的第二个分配在此处进行。
Run这将分配构造 Vec<T>
所需的次数,然后分配一次,以将 Vec<T>
转换为 Arc<[T]>
。
已知长度的迭代器
当您的 Iterator
实现 TrustedLen
且大小正确时,将为 Arc<[T]>
进行一次分配。例如:
let evens: Arc<[u8]> = (0..10).collect(); // 这里只进行一次分配。
Run