关于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

回到顶部