[Day38] Read Rust Atomics and Locks - Build Basic Arc
by Mara Bos
At Topic: Chapter 6. Basic Reference Counting
Recall
Arc
- Goal: To share ownership
- Thread safe (While
Rc
is not) - Immutable (So is
Rc
)
let a = Arc::new([1, 2, 3]); let b = a.clone(); assert_eq!(a.as_ptr(), b.as_ptr()); // Same allocation!
Notes
To see full implementation, please go here. I just write down things that I feel important.
ArcData<T>
is the core unit of Arc
and should not be public
struct ArcData<T> { ref_count: AtomicUsize, data: T }
Arc is basically a pointer to a shared ArcData<T>
object. For this:
Box<ArcData<T>>
is unacceptable because a Box represents exclusive ownership, not shared ownership.- Using reference is also unacceptable because of the lifetime issue (Arc does not follow the lifetime rule).
- Instead,
std::ptr::NonNull<T>
is used which represents a pointer toT
that is never null.
pub struct Arc<T> { ptr: NonNull<ArcData<T>> }
For
pub fn new(data: T) -> Arc<T> { Arc { ptr: NonNull::from(Box::leak(Box::new(ArcData { ref_count: AtomicUsize::new(1), data, }))), } }
-
Using
Box::new()
to allocate memory not&ArcData
because&ArcData
causes lifetime issues. -
Box::leak()
is used to give up the exclusive ownership of the allocation. -
Box::from_raw()
: reclaim exclusive ownership of the allocation (for dropping) -
An
Arc
should not implementDerefMut
since it represents shared ownership. -
When
ref_count == 1
, get mutable reference is possible. -
After changing the value by
get_mut
, we need to use mutex etc. to access the value ofArc
(Actually, I do not understand why it is necessary).