rust学习-Arc

本文介绍了Rust中的Arc(Atomic Reference Counted),一种线程安全的引用计数指针。内容包括Arc的背景、如何打破引用循环、创建Arc、Deref行为以及多个示例,展示了Arc在处理Int32、struct和AtomicUsize等类型的应用。
摘要由CSDN通过智能技术生成

背景介绍

线程安全的引用计数指针。 “Arc”代表“原子引用计数 Atomically Reference Counted”。

Arc 类型提供在堆中分配的 T 类型值的共享所有权(shared ownership)。在 Arc 上调用克隆会生成一个新的 Arc 实例,该实例指向堆上与源 Arc 相同的分配,同时增加引用计数。当指向给定分配的最后一个 Arc 指针被销毁时,存储在该分配中的值(通常称为“内部值”)也会被删除。

Rust 中的共享引用默认不允许mutation,Arc 也不例外:通常无法获得对 Arc 内某些内容的可变引用。如果需要通过 Arc 进行mutate,请使用 Mutex、RwLock 或 Atomic 类型之一。

注意:此类型仅在支持原子加载和指针存储的平台(platforms that support atomic loads and stores of pointers)上可用,其中包括所有支持 std crate 的平台,但不包括所有仅支持 alloc 的平台。这可以在编译时使用 #[cfg(target_has_atomic = “ptr”)] 检测到。

与 Rc 不同,Arc 使用原子操作进行引用计数。这意味着它是线程安全的。缺点disadvantage是原子操作比普通内存访问(ordinary memory accesses)更昂贵。如果不在线程之间共享引用计数分配,请考虑使用 Rc 来降低开销。 Rc 是一个安全的默认值,因为编译器会捕获在线程之间发送 Rc 的任何尝试(catch any attempt to send an Rc between threads)。但是,library可能会选择 Arc 以便为library使用者提供更大的灵活性。

只要 T 实现了Send 和 Sync,Arc 就会实现Send 和 Sync。
为什么不能将非线程安全类型 T 放入 Arc 中以使其成为线程安全的?
乍一看这可能有点违反直觉(a bit counter-intuitive):
毕竟,难道不是 Arc 线程安全的重点吗( isn’t the point of Arc thread safety? )?
关键点是:Arc 使得对同一数据拥有多个所有权(have multiple ownership of the same data)是线程安全的,但它并没有为其数据添加线程安全性。
考虑 Arc<RefCell>。 RefCell 不是Sync的,如果 Arc 始终是Send,则 Arc<RefCell> 也会如此。但这样我们就会遇到一个问题:RefCell 不是线程安全的;它使用非原子操作跟踪借用计数(keeps track of the borrowing count using non-atomic operations)。

最后,这意味着可能需要将 Arc 与某种 std::sync 类型(通常是 Mutex)配对使用(pair Arc with some sort of std::sync type, usually Mutex)。

Breaking cycles with Weak

用 Weak 打破cycle
downgrade 方法可用于创建非拥有的 Weak 指针(a non-owning Weak pointer)。弱指针(Weak pointer)可以升级为 Arc,但如果存储在分配(allocation)中的值已被删除,这将返回 None。换句话说,弱指针不会使分配内的值保持 active 状态;但是,它们确实使allocation(值的后端存储?)保持 active 状态(they do keep the allocation (the backing store for the value) alive)。

Arc 指针之间的循环永远不会被释放。因此,使用Weak来打破循环。例如,一棵树可以具有从父节点到子节点的强Arc指针,以及从子节点返回到其父节点的Weak指针。

创建

使用 Clone trait 给 Arc 和 Weak

impl<T> Clone for Arc<T>
where
    T: ?Sized,
fn clone(&self) -> Arc<T>
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, and foo are all Arcs that point to the same memory location

Deref behavior

在 Arc 上可以调用 T 的方法,因为 Arc 自动解引用到 T
为了避免与 T 的方法发生名称冲突,Arc 本身的方法是关联函数,使用完全限定语法(fully qualified syntax)进行调用:

use std::sync:
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值