繁体   English   中英

如何检查一个线程是否在 Rust 中完成?

[英]How to check if a thread has finished in Rust?

当我在 Rust 中spawn一个线程时,我得到了一个JoinHandle ,它非常适合......加入(一个阻塞操作),而不是其他。 如何检查子线程是否已从父线程退出(即JoinHandle.join()不会阻塞)? 如果您知道如何杀死子线程,则可以加分。

我想你可以通过创建一个通道、向孩子发送一些东西并捕获错误来做到这一点,但这似乎是不必要的复杂性和开销。

从 Rust 1.7 开始,标准库中没有 API 可以检查子线程是否已退出而没有阻塞。

一种可移植的解决方法是使用通道从孩子向父母发送消息,以表明孩子即将退出。 Receiver有一个非阻塞的try_recv方法。 try_recv确实收到一条消息时,您可以使用JoinHandle上的join()来检索线程的结果。

还有一些不稳定的特定于平台的扩展特性,可让您获得原始线程句柄。 然后,您必须编写特定于平台的代码来测试线程是否已退出。

如果你认为这个特性应该在 Rust 的标准库中,你可以提交一个 RFC (一定要先阅读 README!)。

如果您知道如何杀死子线程,则可以加分。

Rust 中的线程是使用本机操作系统线程实现的。 尽管操作系统可能会提供一种杀死线程的方法,但这样做并不是一个好主意,因为线程分配的资源在进程结束之前不会被清理。

这是可能的,朋友们。 使用Rust会在endpanic时丢弃的 refcounters。 100% 安全。 例子:

use std::time::Duration;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;

fn main() {
    // Play with this flag
    let fatal_flag = true;
    let do_stop = true;

    let working = Arc::new(AtomicBool::new(true));
    let control = Arc::downgrade(&working);

    thread::spawn(move || {
        while (*working).load(Ordering::Relaxed) {
            if fatal_flag {
                panic!("Oh, my God!");
            } else {
                thread::sleep(Duration::from_millis(20));
                println!("I'm alive!");
            }
        }
    });

    thread::sleep(Duration::from_millis(50));

    // To stop thread
    if do_stop {
        match control.upgrade() {
            Some(working) => (*working).store(false, Ordering::Relaxed),
            None => println!("Sorry, but thread died already."),
        }
    }

    thread::sleep(Duration::from_millis(50));

    // To check it's alive / died
    match control.upgrade() {
        Some(_) => println!("Thread alive!"),
        None => println!("Thread ends!"),
    }
}

要点: https ://gist.github.com/DenisKolodin/edea80f2f5becb86f718c330219178e2

在操场上: https ://play.rust-lang.org/?gist=9a0cf161ba0bbffe3824b9db4308e1fb&version=stable&backtrace=0

UPD :我创建了实现这种方法thread-control箱: https ://github.com/DenisKolodin/thread-control

简短的答案是不可能的。 但这不是真正应该解决的问题。

如果您知道如何杀死子线程,则可以加分。

绝不

即使在支持杀死线程的语言中( 请参阅此处的 Java ),也建议不要这样做。

线程的执行通常使用显式的交互点进行编码,并且通常会隐含假设不会发生其他中断。

最令人震惊的例子当然是资源:天真的“杀死”方法是停止执行线程; 这意味着不释放任何资源。 您可能会想到记忆,这是您最不担心的事情。 相反,想象一下,所有未解锁的Mutex将在以后创建死锁......

另一种选择是在线程中注入panic ,这将导致展开。 但是,您不能在任何时候开始放松! 程序必须定义安全点,在这些点注入panic可以保证是安全的(在任何其他点注入恐慌都意味着可能破坏共享对象); 如何定义这样的安全点并注入panic在本地语言中存在一个开放的研究问题,尤其是在系统W^X上执行的那些(其中内存页面是可写的或可执行的,但绝不是两者)。

总之,没有已知的方法可以安全地(无论是在内存方面还是在功能方面)杀死一个线程。

我觉得Arc可以用来解决这个问题如果线程退出,引用计数器减一

从 rust 1.61.0 开始,有一个is_finished方法。

https://doc.rust-lang.org/stable/std/thread/struct.JoinHandle.html#method.is_finished

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM