Rust for cpp devs - 线程

2021-05-19  本文已影响0人  找不到工作

由于 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");
}
上一篇下一篇

猜你喜欢

热点阅读