use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| { // keep a handle of thread
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap(); // wait for spawned thread to finish
}
move
Closures with ThreadsSince Rust will infer the closure’s trait, one needs to use move
to make closures acquire environments by taking ownership. In below example, if there is no move
, the closure will implement Fn
because Rust thinks (by analyzing closure body) the closure does not need ownership. As a result, Rust thinks the borrow of v
in closure might outlive the v
outside (Rust does not know how long the closure will live.)
use std::thread;
fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
handle.join().unwrap();
}
We create a new channel using the mpsc::channel
function; mpsc
stands for multiple producer, single consumer.
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || { // this thread needs to own the tx to send messages
let val = String::from("hi");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap(); // recv blocks main thread; use try_recv for non-blocking purpose.
println!("Got: {}", received);
}
A channel is said to be closed if either the transmitter or receiver half is dropped.
Below code won’t compile:
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
println!("val is {}", val); // borrow after moved
});
let received = rx.recv().unwrap();
println!("Got: {}", received);
}
In a way, channels in any programming language are similar to single ownership, because once you transfer a value down a channel, you should no longer use that value. Shared memory concurrency (e.g. mutexes) is like multiple ownership: multiple threads can access the same memory location at the same time.
Mutex<T>
use std::sync::Mutex;
fn main() {
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap(); // we must call lock to get the inner value
*num = 6;
}
println!("m = {:?}", m);
}
Mutex<T>
Between Multiple ThreadsBelow code won’t compile:
use std::sync::Mutex;
use std::thread;
fn main() {
let counter = Mutex::new(0);
let mut handles = vec![];
for _ in 0..10 {
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap(); // counter is moved
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}