Struct alloc::sync::Arc 1.0.0[−][src]
pub struct Arc<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 都是指向同一内存位置的 ArcRunDeref 行为
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
获取 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