由于 Rust 特有的 ownership 和类型检查机制,许多并发问题都可以在编译期发现,这极大地降低了风险以及 debug 难度。因此,Rust 这个特性被称为“无畏的并发”。
Thread
由于 Rust runtime 比较简单,因此 Rust 标准库只实现了系统级线程(thread),而没有实现用户级线程(coroutine)。
使用 spawn 创建线程
spawn
方法接收一个可执行的 closure,开启一个新的线程并开始执行这个 closure:
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn( || {
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));
}
}
输出结果是:
hi number 1 from the main thread!
hi number 1 from the spawned thread!
hi number 2 from the main thread!
hi number 2 from the spawned thread!
hi number 3 from the main thread!
hi number 3 from the spawned thread!
hi number 4 from the main thread!
hi number 4 from the spawned thread!
hi number 5 from the spawned thread!
我们发现,新建的线程中的函数并没有执行完毕。这是因为 spawn
创建的线程默认是 detach 运行的,我们需要 join 这个新的线程。
实际上,spawn
函数会返回一个 JoinHandle
,它提供了一个 join
方法,保证在 join
过后该线程的操作全部完成。
use std::thread;
use std::time::Duration;
fn main() {
let join_handle = thread::spawn(|| {
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));
}
join_handle
.join()
.expect("Couldn't join on the associated thread");
}
输出结果是:
hi number 1 from the main thread!
hi number 1 from the spawned thread!
hi number 2 from the main thread!
hi number 2 from the spawned thread!
hi number 3 from the main thread!
hi number 3 from the spawned thread!
hi number 4 from the main thread!
hi number 4 from the spawned thread!
hi number 5 from the spawned thread!
hi number 6 from the spawned thread!
hi number 7 from the spawned thread!
hi number 8 from the spawned thread!
hi number 9 from the spawned thread!
使用 move 关键字
有时候,我们需要在新的线程中使用当前环境的变量,比如下面的例子,我们希望能在另一个线程打印这个数组:
fn use_move() {
let v = vec![1, 2, 3];
let handle = thread::spawn(|| {
println!("Here's a vector: {:?}", v);
});
handle
.join()
.expect("Couldn't join on the associated thread");
}
编译报错:
error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function
--> src/main.rs:24:33
|
24 | let handle = thread::spawn( || {
| ^^ may outlive borrowed value `v`
25 | println!("Here's a vector: {:?}", v);
| - `v` is borrowed here
|
note: function requires argument type to outlive `'static`
因为 closure 中只有 println!
,因此捕获变量时只采用了“常值引用”方式,然而,Rust 无法知道子线程会运行多久,因此无法确定 v
是否能全程保持有效。
此时,如同我们在 Rust for cpp devs - closure 中讲的,我们可以使用 move
关键字强制 closure 拿走 v
的 ownership。
fn use_move() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || { // add 'move' here
println!("Here's a vector: {:?}", v);
});
handle
.join()
.expect("Couldn't join on the associated thread");
}
网友评论