The other answer solves the problem for any type, but as pnkfelix observes, atomic wrapper types are another solution that will work for the specific case of i32
.
Since Rust 1.0, you can use AtomicBool
, AtomicPtr<T>
, AtomicIsize
and AtomicUsize
to synchronize multi-threaded access to bool
, *mut T
, isize
and usize
values. In Rust 1.34, several new Atomic
types have been stabilized, including AtomicI32
. (Check the std::sync::atomic
documentation for the current list.)
Using an atomic type is most likely more efficient than locking a Mutex
or RwLock
, but requires more attention to the low-level details of memory ordering. If your threads share more data than can fit in one of the standard atomic types, you probably want a Mutex
instead of multiple Atomic
s.
That said, here's a version of kennytm's answer using AtomicI32
instead of Mutex<i32>
:
use std::sync::{
atomic::{AtomicI32, Ordering},
Arc,
};
use std::thread;
use std::time::Duration;
fn main() {
let num = Arc::new(AtomicI32::new(5));
let num_clone = num.clone();
thread::spawn(move || loop {
num.fetch_add(1, Ordering::SeqCst);
thread::sleep(Duration::from_secs(10));
});
output(num_clone);
}
fn output(num: Arc<AtomicI32>) {
loop {
println!("{:?}", num.load(Ordering::SeqCst));
thread::sleep(Duration::from_secs(5));
}
}
Arc
is still required for shared ownership (but see How can I pass a reference to a stack variable to a thread?).
Choosing the right memory Ordering
is far from trivial. SeqCst
is the most conservative choice, but if there is only one memory address being shared, Relaxed
should also work. See the links below for more information.
Links
std::sync::atomic
module documentation
- Atomics (chapter of The Rustonomicon)
- LLVM Memory Model for Concurrent Operations and Atomic Instructions and Concurrency Guide