[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
Rcis 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 toTthat 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&ArcDatabecause&ArcDatacauses 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
Arcshould not implementDerefMutsince 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).