代码编译执行后结果如下:

文章插图
主线程会等待直到新建线程执行完毕之后才开始执行 for 循环 , 所以输出将不会交替出现 。
因此,将join放在代码的不同地方, 将会影响线程是否同时执行 。
4.将move闭包与线程一起使用move 关键字经常用于传递给 thread::spawn 的闭包,因为闭包会获取从环境中取得的值的所有权 , 因此会将这些值的所有权从一个线程传送到另一个线程 。
为了在新建线程中使用来自于主线程的数据,需要新建线程的闭包获取它需要的值, 下面的代码展示了一个尝试在主线程中创建一个 vector 并用于新建线程的例子,不过这么写还不能工作, 代码如下:
use std::thread;fn main() {let v = vec![1, 2, 3];let handle = thread::spawn(|| {println!("Here's a vector: {:?}", v);});handle.join().unwrap();}闭包使用了 v,所以闭包会捕获 v 并使其成为闭包环境的一部分 。因为 thread::spawn 在一个新线程中运行这个闭包 , 所以可以在新线程中访问 v 。然而当编译这个例子时,会得到如下错误:
文章插图
Rust 会 推断 如何捕获 v,因为 println! 只需要 v 的引用 , 闭包尝试借用 v 。然而这有一个问题:Rust 不知道这个新建线程会执行多久,所以无法知晓对 v 的引用是否一直有效 。
看一段比较极端情况的代码:
use std::thread;fn main() {let v = vec![1, 2, 3];let handle = thread::spawn(|| {println!("Here's a vector: {:?}", v);});drop(v); // 坏事儿了!handle.join().unwrap();}如果 Rust 允许这段代码运行,则新建线程则可能会立刻被转移到后台并完全没有机会运行 。新建线程内部有一个 v 的引用,不过主线程立刻就使用drop丢弃了v 。接着当新建线程开始执行,v 已不再有效,所以其引用也是无效的 。为了修复上面的编译错误, 我们可以根据编译器给予我们的help尝试修正一下,如图:

文章插图
通过在闭包之前增加 move 关键字,强制闭包获取其使用的值的所有权,而不是任由 Rust 推断它应该借用值 。
修正后的代码如下:
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();}编译运行试一下:
文章插图
看起来没问题,那么以这个成功的经验, 修改那段极端情况的代码如下:
use std::thread;fn main() {let v = vec![1, 2, 3];let handle = thread::spawn(move || {println!("Here's a vector: {:?}", v);});drop(v); // 坏事儿了!handle.join().unwrap();}再次编译一下看看结果如何:
文章插图
Rust编译器依然没有放行, 这个修复行不通 。
如果为闭包增加 move,将会把 v 移动进闭包的环境中, 因此将不能在主线程中对其调用 drop 了, Rust 的所有权规则又一次帮助我们杜绝了隐患 。因为 Rust 是保守的并只会为线程借用 v,这意味着主线程理论上可能使新建线程的引用无效 。通过告诉 Rust 将 v 的所有权移动到新建线程,我们向 Rust 保证主线程不会再使用 v 。如果对其作出同样的move修改, 那么当在主线程中使用 v 时就会违反所有权规则 。move 关键字覆盖了 Rust 默认保守的借用,但它不允许我们违反所有权规则 。
【在 Rust 编程中使用多线程】
推荐阅读
- 只有了解关键词排名机制,才可以避免走入网站优化深渊
- 秀米该咋滴才可以上传视频,如何在秀米编辑器中上传图片
- 在哪里开失业证明?
- 男性器官衰老顺序已公开,建议对照一下,看看自己在哪个阶段?
- 医用酒精喷在食物上 医用酒精喷到食物上还可以吃吗
- 猫在楼道里丢了怎么找,猫咪丢了怎么快速找回
- 披着军旅外衣的6部烂剧,每部都在侮辱观众智商
- 端午扫帚挂件应该挂在哪里 端午节扫帚挂哪里
- 白素贞为什么怕端午节 白素贞在端午节那天喝了什么
- 多肉砍头后怎么处理
