Rust从入门到实战系列一百八十六:使用 spawn 创建新线程

为了创建一个新线程,需要调用 thread::spawn 函数并传递一个闭包(第十三章学习了闭包),并在其
中包含希望在新线程运行的代码。示例 16-1 中的例子在主线程打印了一些文本而另一些文本则由新线
程打印:
文件名: src∕main.rs
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));
}
}
示例 16-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!
thread::sleep 调用强制线程停止执行一小段时间,这会允许其他不同的线程运行。这些线程可能会轮流
运行,不过并不保证如此:这依赖操作系统如何调度线程。在这里,主线程首先打印,即便新创建线程
的打印语句位于程序的开头,甚至即便我们告诉新建的线程打印直到 i 等于 9 ,它在主线程结束之前也
只打印到了 5。
如果运行代码只看到了主线程的输出,或没有出现重叠打印的现象,尝试增大区间 (变量 i 的范围) 来增
加操作系统切换线程的机会。
使用 join 等待所有线程结束
由于主线程结束,示例 16-1 中的代码大部分时候不光会提早结束新建线程,甚至不能实际保证新建线程
会被执行。其原因在于无法保证线程运行的顺序!
可以通过将 thread::spawn 的返回值储存在变量中来修复新建线程部分没有执行或者完全没有执行的问
题。thread::spawn 的返回值类型是 JoinHandle。JoinHandle 是一个拥有所有权的值,当对其调用 join
方法时,它会等待其线程结束。示例 16-2 展示了如何使用示例 16-1 中创建的线程的 JoinHandle 并调
用 join 来确保新建线程在 main 退出前结束运行:
文件名: src∕main.rs
use std::thread;
use std::time::Duration;
fn main() {
let 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));
}
handle.join().unwrap();
}
示例 16-2: 从 thread::spawn 保存一个 JoinHandle 以确保该线程能够运行至结束
通过调用 handle 的 join 会阻塞当前线程直到 handle 所代表的线程结束。阻塞(Blocking)线程意味着
阻止该线程执行工作或退出。因为我们将 join 调用放在了主线程的 for 循环之后,运行示例 16-2 应该
会产生类似这样的输出:
hi number 1 from the main thread!
hi number 2 from the main thread!
hi number 1 from the spawned thread!
hi number 3 from the main thread!
hi number 2 from the spawned thread!
hi number 4 from the main thread!
hi number 3 from the spawned 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!
这两个线程仍然会交替执行,不过主线程会由于 handle.join() 调用会等待直到新建线程执行完毕。
不过让我们看看将 handle.join() 移动到 main 中 for 循环之前会发生什么,如下:
文件名: src∕main.rs
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1…10 {
println!(“hi number {} from the spawned thread!”, i);
thread::sleep(Duration::from_millis(1));
}
});
handle.join().unwrap();
for i in 1…5 {
println!(“hi number {} from the main thread!”, i);
thread::sleep(Duration::from_millis(1));
}
}
主线程会等待直到新建线程执行完毕之后才开始执行 for 循环,所以输出将不会交替出现,如下所示:
hi number 1 from the spawned thread!
hi number 2 from the spawned thread!
hi number 3 from the spawned 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!
hi number 1 from the main thread!
hi number 2 from the main thread!
hi number 3 from the main thread!
hi number 4 from the main thread!
诸如将 join 放置于何处这样的小细节,会影响线程是否同时运行。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值