Data Races — Atomic Rust.
A Problem With Reference Counters And Multi-Threaded Rust.
Data Race
A data race occurs in multi-threaded programming when two or more threads access shared data at the same time, and at least one of the accesses is a write.
Without proper synchronization, this can lead to unpredictable behavior such as corrupted data, crashes (panics in rust), lost updates, etc.

Reference Counter
Rust’s built-in Reference Counter (std::rc::Rc
) allows us to make multiple references to a single piece of data.
You could store an array inside an Rc<T>
, clone it, and call the get pointer method on both the original and clone and you will get same pointer each time.
use std::rc::Rc;
let a = Rc::new([1, 2, 3]);
let b = a.clone();
assert_eq!(a.as_ptr(), b.as_ptr()); // Same allocation!
Now, this code above will work perfectly fine given that both the original and cloned data is accessed within the same thread.
But, would it work when we try to access it across a different thread? Unfortunately no, It won’t.
| error[E0277]: `Rc` cannot be sent between threads safely
8 |
| thread::spawn(move || dbg!(b));
This error occurs because Rc<T>
does not implement the Send
trait, which is required to move data between threads. Rc<T>
is designed for single-threaded scenarios only.
Atomic Reference Counter
One solution is to use an atomic reference counter, Arc<T>
, instead of Rc<T>
.
Arc<T>
is thread-safe because it performs reference count modifications using atomic operations, ensuring that access across threads is safe.
The term Atomic in programming refers to something related to threads or concurrency.

use std::sync::Arc;
use std::thread;
let a = Arc::new([1, 2, 3]);
let b = a.clone();
thread::spawn(move || dbg!(a));
thread::spawn(move || dbg!(b));
Conclusion
In summary, both Rc<T>
and Arc<T>
in the Rust standard library are designed to prevent data races, given that they’re used with a Mutex<T>
. The Arc-Mutex does this by making sure there is only one mutable reference at once.