Reputation: 359
I notice that Rust's Atomic*
structs have functions which modify the value, such as fetch_add
. For instance, I can write this program:
use std::sync::atomic::{AtomicUsize, Ordering};
struct Tester {
counter: AtomicUsize
}
impl Tester {
fn run(&self) {
let counter = self.counter.fetch_add(1, Ordering::Relaxed);
println!("Hi there, this has been run {} times", counter);
}
}
fn main() {
let t = Tester { counter: AtomicUsize::new(0) };
t.run();
t.run();
}
This compiles and runs fine, but if I change the AtomicUsize
to a normal integer, it will (correctly) fail to compile due to mutability concerns:
struct Tester {
counter: u64
}
impl Tester {
fn run(&self) {
self.counter = self.counter + 1;
println!("Hi there, this has been run {} times", self.counter);
}
}
Upvotes: 15
Views: 1804
Reputation: 90852
It wouldn’t be very useful if it didn’t work this way. With &mut
references, only one can exist at a time, and no &
references at that time, so the whole question of atomicity of operation would be moot.
Another way of looking at it is &mut
are unique references, and &
aliasable references. For normal types, mutation can only safely occur if you have a unique reference, but atomic types are all about mutation (via replacement) without needing a unique reference.
The naming of &
and &mut
has been a fraught matter, with much fear, uncertainty and doubt in the community and documents like Focusing on Ownership explaining how things actually are. The language has ended up staying with &
and &mut
, but &mut
is actually about uniqueness rather than mutability (it’s just that most of the time the two are equivalent).
Upvotes: 23