关于Rust中std::thread::JoinHandle::join方法的疑惑?
祝大家中秋节快乐
《八月十五日夜湓(Pén)亭望月》 - 唐·白居易 昔年八月十五夜,曲江池畔杏园边。
今年八月十五夜,湓浦沙头水馆前。
西北望乡何处是,东南见月几回圆。
昨风一吹无人会,今夜清光似往年。
描述:
下面的代码源自 Rust By Example - Channels
其中的一些注释能够帮助理解代码含义
use std::sync::mpsc::{Sender, Receiver};use std::sync::mpsc;
use std::thread;
static NTHREADS: i32 = 3;
fn main() {
// Channels have two endpoints: the `Sender<T>` and the `Receiver<T>`,
// where `T` is the type of the message to be transferred
// (type annotation is superfluous)
let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
let mut children = Vec::new();
for id in 0..NTHREADS {
// The sender endpoint can be copied
let thread_tx = tx.clone();
// Each thread will send its id via the channel
let child = thread::spawn(move || {
// The thread takes ownership over `thread_tx`
// Each thread queues a message in the channel
thread_tx.send(id).unwrap();
// Sending is a non-blocking operation, the thread will continue
// immediately after sending its message
println!("thread {} finished", id);
});
children.push(child);
}
// Here, all the messages are collected
let mut ids = Vec::with_capacity(NTHREADS as usize);
for _ in 0..NTHREADS {
// The `recv` method picks a message from the channel
// `recv` will block the current thread if there are no messages available
ids.push(rx.recv());
}
// Wait for the threads to complete any remaining work
for child in children {
child.join().expect("oops! the child thread panicked");
}
// Show the order in which the messages were sent
println!("{:?}", ids);
}
下面的代码和上面相同,只是我把上面的
代码的英文注释删除,并添加自己的注解说明;自己添加的这些注解可能会有错误或者不严谨,同时也在注解提出自己的疑惑
static NTHREADS: i32 = 3;fn main() {
let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
let mut children = Vec::new();
for id in 0..NTHREADS {
let thread_tx = tx.clone();
//创建线程并执行,同时返回JoinHandle结构体
//关于thread::spawn的说明下面有链接
let child = thread::spawn(move || {
//关于 std::sync::mpsc::channel send的说明下面有链接
thread_tx.send(id).unwrap();
println!("thread {} finished", id);
});
children.push(child);
}
let mut ids = Vec::with_capacity(NTHREADS as usize);
for _ in 0..NTHREADS {
//如果没有消息可读的时候;recv方法会阻塞当前线程(也就是main线程)的执行;
//也就是说当前 for 循环执行完之后;我们可以确定的是 前面创建的线程都已经执行完毕,不然main线程就会卡在这里等消息
ids.push(rx.recv());
}
for child in children {
//关于JoinHandle详细说明下面有链接
//`child 是 JoinHandle 类型;child.join的作用是:保证每个JoinHandel所关联的线程在每个child.join执行的时候是执行完毕的`,不然当前main线程就会等待JoinHandel所关联线程执行完毕
//同时join方法会返回Result类型,从这个类型中我们可以判断我们给子线程的任务是否执行成功,如果执行成功也可获取其返回值;
//我的疑惑是:: 当代码执行到这个for循环的时候就说明前面的每一个线程已经正确执行完毕,前一个for循环可以保证执行完毕这一点, 而 我们派发给每个线程的任务只是 简单的发一条消息,这个任务出错,或carsh,或panic 可能性很小; 那么这里我们是否可以省略掉 当前这个for循环中的代码?
child.join().expect("oops! the child thread panicked");
}
println!("{:?}", ids);
}
std::thread::spawn
std::sync::mpsc::channel send
std::thread::JoinHandle,
扩展
- channel 中 send方法什么时候会出错? 这些错误可以在 JoinHandle的Join方法中捕获吗?
- Rust中 OS线程的任务中如果有加锁的情况,可是这个任务出错了,那么需要在 JoinHandle的Join方法中捕获这个错误并解锁吗?
- OS线程的任务不会panic,或者抛异常,那么这个线程肯定回执行成功?
- 多线程安全还要注意哪些方面?
期望
- 可以回答你所熟悉的关于多线程安全的其他一些内容。
- 希望有理有据,尽可能给出参考链接,或者其他有说服力的资料,
感谢在先
。
Refs
Rust By Example - Channels
回答:
接受到消息并不能保证线程已经退出了,只说明对应线程的 send 已经调用了。所以要 join 保证线程也结束了。
以上是 关于Rust中std::thread::JoinHandle::join方法的疑惑? 的全部内容, 来源链接: utcz.com/p/944708.html