Chapter 6. Building Our Own “Arc”

In “Reference Counting”, we saw the std::sync::Arc<T> type that allows for shared ownership through reference counting. The Arc::new function creates a new allocation, just like Box::new. However, unlike a Box, a cloned Arc will share the original allocation, without creating a new one. The shared allocation will only be dropped once the Arc and all its clones are dropped.

The memory ordering considerations involved in an implementation of this type can get quite interesting. In this chapter, we’ll put more of the theory to practice by implementing our own Arc<T>. We’ll start with a basic version, then extend it to support weak pointers for cyclic structures, and finish the chapter with an optimized version that’s nearly identical to the implementation in the standard library.

Basic Reference Counting

Our first version will use a single AtomicUsize to count the number of Arc objects that share an allocation. Let’s start with a struct that holds this counter and the T object:

struct ArcData<T> {
    ref_count: AtomicUsize,
    data: T,
}

Note that this struct is not public. It’s an internal implementation detail of our Arc implementation.

Next is the Arc<T> struct itself, which is effectively just a pointer to a (shared) ArcData<T> object.

It might be tempting to make it a wrapper for a Box<ArcData<T>>, using a standard Box to handle the allocation of the ArcData<T>. However, a Box represents exclusive ownership, not shared ownership. We can’t use ...

Get Rust Atomics and Locks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.