
Rust 中的线程与其他语言中的线程工作方式类似。
Rust
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 0..10 {
println!("Count in thread: {i}!");
thread::sleep(Duration::from_millis(5));
}
});
for i in 0..5 {
println!("Main thread: {i}");
thread::sleep(Duration::from_millis(5));
}
}
输出如下:
Rust
// Output
Main thread: 0
Count in thread: 0!
Main thread: 1
Count in thread: 1!
Main thread: 2
Count in thread: 2!
Main thread: 3
Count in thread: 3!
Main thread: 4
Count in thread: 4!
生成新线程不会在 main
函数末尾阻塞直到程序终止。
线程 panic
彼此独立,在新线程中触发一个 panic
,不会使主线程 panic
。
上述代码主线程结束了程序,而生成线程并不会使程序继续运行,所以计数到 4
程序就终止了。
我们如何等待生成的线程完成呢?
thread::spawn
会返回一个 JoinHandle
。
JoinHandle
有一个 .join()
方法,该方法会阻塞线程。
使用 let handle = thread::spawn(...)
,然后在后面调用 handle.join()
来等待线程完成,以使程序能完整地数到 9
。
Rust
fn main() {
let handle = thread::spawn(|| {
for i in 0..10 {
println!("Count in thread: {i}!");
thread::sleep(Duration::from_millis(5));
}
});
for i in 0..5 {
println!("Main thread: {i}");
thread::sleep(Duration::from_millis(5));
}
handle.join();
}
如果我们想返回一个值呢?
thread::spawn
的闭包返回 T
,JoinHandle
的 .join()
方法返回 thread::Result<T>
使用 handle.join()
的 Result
返回值来获取返回的值:
Rust
fn main() {
let handle = thread::spawn(|| {
1 + 3
});
println!("{}",handle.join().unwrap());
}
// Output
// 4
好的,现在我们可以从线程中返回值了!那接收输入该怎么做呢?
Rust
fn main() {
let adder = 4;
let handle = thread::spawn(|| { // compile error: may outlive borrowed value `adder`
1 + adder
});
println!("{}", handle.join().unwrap());
}
我们尝试通过借用的方式,将 adder
借用到线程中使用,这段代码并不能通过编译。原因很简单,线程可能活的比 adder
更长,所以,这里需要转移所有权:
Rust
fn main() {
let adder = 4;
let handle = thread::spawn(move || {
1 + adder
});
println!("{}", handle.join().unwrap());
}
// Output
// 5
如果你还是想借用,作用域线程可能正是你想要的:
Rust
fn main() {
let adder = 4;
thread::scope(|scope| {
let handle = scope.spawn(|| {
1 + adder
});
println!("{}", handle.join().unwrap());
});
}
当 thread::scope
函数执行完成时,所有 scope.spawn
生成的线程都必定已经完成,所以这些线程能够借用数据。
正常的 Rust 借用规则在此同样适用:你要么让一个线程可变地借用数据,要么让任意数量的线程不可变地借用数据。