基本代码(Base Code)

现在我们已经确定了Arc实现的布局,让我们创建一些基本代码。

构建Arc(Constructing the Arc)

我们首先需要一种构造Arc<T>的方法。

这非常简单,因为我们只需要将ArcInner<T>框起来,并获得一个指向它的NonNull<T>指针。

  1. impl<T> Arc<T> {
  2. pub fn new(data: T) -> Arc<T> {
  3. // We start the reference count at 1, as that first reference is the
  4. // current pointer.
  5. let boxed = Box::new(ArcInner {
  6. rc: AtomicUsize::new(1),
  7. data,
  8. });
  9. Arc {
  10. // It is okay to call `.unwrap()` here as we get a pointer from
  11. // `Box::into_raw` which is guaranteed to not be null.
  12. ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
  13. phantom: PhantomData,
  14. }
  15. }
  16. }

Send和Sync

因为我们正在构建一个并发原语,所以我们需要能够跨线程发送它。因此,我们可以实现SendSync标记trait。有关这些的更多信息,请参阅SendSync一节

这很好,因为:

  • 只有当且仅当它是引用该数据的唯一Arc时,您才能获得对Arc内值的可变引用(这只发生在Drop中)

  • 我们使用原子进行共享的可变引用计数

  1. unsafe impl<T: Sync + Send> Send for Arc<T> {}
  2. unsafe impl<T: Sync + Send> Sync for Arc<T> {}

我们需要限定T: Sync + Send,因为如果我们不提供这些边界,就有可能通过Arc跨线程边界共享线程不安全的值,这可能会导致数据竞争或不健全。

例如,如果这些限定不存在,Arc<Rc<u32>> 将是 SyncSend,这意味着你可以从 Arc 中克隆出 Rc 以通过线程发送它 (不创建一个全新的 Rc),这将创建数据竞争,因为 Rc 不是线程安全的。

获取ArcInner

要将NonNull<T>指针解引用为&T,我们可以调用NonNull::as_ref。 这是不安全的,不像典型的as_ref函数,所以我们必须像这样调用它:

  1. unsafe { self.ptr.as_ref() }

我们将在此代码中多次使用此代码段(通常使用一个关联的 let 绑定)。

这种不安全是没有问题的,因为当这个Arc存在时,我们保证内部指针是有效的。

Deref

好的。 现在我们可以制作Arcs(很快就能正确地克隆和销毁它们),但是我们如何获取里面的数据呢?

我们现在需要的是Deref的一个实现。

我们需要导入trait:

  1. use std::ops::Deref;

这是实现:

  1. impl<T> Deref for Arc<T> {
  2. type Target = T;
  3. fn deref(&self) -> &T {
  4. let inner = unsafe { self.ptr.as_ref() };
  5. &inner.data
  6. }
  7. }

很简单吧? 这只是对指向ArcInner<T>NonNull指针进行解引用,然后获取对内部数据的引用。

代码

这是本节的所有代码:

  1. use std::ops::Deref;
  2. impl<T> Arc<T> {
  3. pub fn new(data: T) -> Arc<T> {
  4. // We start the reference count at 1, as that first reference is the
  5. // current pointer.
  6. let boxed = Box::new(ArcInner {
  7. rc: AtomicUsize::new(1),
  8. data,
  9. });
  10. Arc {
  11. // It is okay to call `.unwrap()` here as we get a pointer from
  12. // `Box::into_raw` which is guaranteed to not be null.
  13. ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
  14. phantom: PhantomData,
  15. }
  16. }
  17. }
  18. unsafe impl<T: Sync + Send> Send for Arc<T> {}
  19. unsafe impl<T: Sync + Send> Sync for Arc<T> {}
  20. impl<T> Deref for Arc<T> {
  21. type Target = T;
  22. fn deref(&self) -> &T {
  23. let inner = unsafe { self.ptr.as_ref() };
  24. &inner.data
  25. }
  26. }