I'm new to Rust and threading and I'm trying to print out a number while adding to it in another thread. How can I accomplish this?
use std::thread;
use std::time::Duration;
fn main() {
let mut num = 5;
thread::spawn(move || {
loop {
num += 1;
thread::sleep(Duration::from_secs(10));
}
});
output(num);
}
fn output(num: i32) {
loop {
println!("{:?}", num);
thread::sleep(Duration::from_secs(5));
}
}
The above code doesn't work: it always prints 5
as if the number is never incremented.
Please read the "Shared-State Concurrency" chapter of The Rust Book, it explains how to do this in detail.
In short:
num
is copied, sooutput()
and the thread operate on different copies of the number. The Rust compiler will fail to compile with an error ifnum
is not copyable.Arc
(atomic reference-counted variable)Arc
, you need to put it in aMutex
orRwLock
. You use the.lock()
method to obtain a mutable reference out of aMutex
. The method will ensure exclusive access across the whole process during the lifetime of that mutable reference.You may also want to read:
Arc<Mutex<i32>>
instead ofArc<i32>
)Arc<Mutex<i32>>
instead ofMutex<i32>
)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
andAtomicUsize
to synchronize multi-threaded access tobool
,*mut T
,isize
andusize
values. In Rust 1.34, several newAtomic
types have been stabilized, includingAtomicI32
. (Check thestd::sync::atomic
documentation for the current list.)Using an atomic type is most likely more efficient than locking a
Mutex
orRwLock
, 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 aMutex
instead of multipleAtomic
s.That said, here's a version of kennytm's answer using
AtomicI32
instead ofMutex<i32>
: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