Multithreading 如何检查螺纹是否生锈?

Multithreading 如何检查螺纹是否生锈?,multithreading,rust,Multithreading,Rust,当我产生一个生锈的线程时,我会得到一个JoinHandle,这对。。。连接(阻塞操作),而不是其他。如何检查子线程是否已从父线程退出(即,JoinHandle.join()不会阻止)?如果您知道如何杀死子线程,将获得额外点数 我想您可以通过创建一个通道、向子线程发送某些内容并捕获错误来实现这一点,但这似乎是不必要的复杂性和开销。从Rust 1.7开始,标准库中没有API来检查子线程是否已无阻塞退出 一个可移植的解决方法是使用从孩子向家长发送消息,以表示孩子即将退出。有一个非阻塞方法。当try\u

当我
产生一个生锈的线程时,我会得到一个
JoinHandle
,这对。。。连接(阻塞操作),而不是其他。如何检查子线程是否已从父线程退出(即,
JoinHandle.join()
不会阻止)?如果您知道如何杀死子线程,将获得额外点数


我想您可以通过创建一个通道、向子线程发送某些内容并捕获错误来实现这一点,但这似乎是不必要的复杂性和开销。

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

一个可移植的解决方法是使用从孩子向家长发送消息,以表示孩子即将退出。有一个非阻塞方法。当
try\u recv
确实收到消息时,您可以使用
JoinHandle
上的
join()
来检索线程的结果

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

如果你认为这个特性应该在Rust的标准库中,你可以(一定要先阅读自述文件!)

如果您知道如何杀死子线程,将获得额外点数


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

简短的答案还不可能。但这并不是真正需要解决的问题

如果您知道如何杀死子线程,将获得额外点数

从不

即使在支持终止线程()的语言中,也建议不要这样做

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

最令人震惊的例子当然是资源:天真的“kill”方法是停止执行线程;这意味着不释放任何资源。你可能会想到记忆,这是你最不担心的。相反,想象一下,所有的
互斥锁
都没有解锁,稍后会产生死锁

另一个选项是在线程中注入一个
panic
,这将导致解卷。然而,你不能在任何时候开始退绕!程序必须定义安全点,在该点注入
恐慌
将保证安全(在任何其他点注入它意味着可能损坏共享对象);如何定义这样的安全点并注入
恐慌
在本地语言中,尤其是在系统
W^X
上执行的语言(其中内存页可以写也可以执行,但决不能两者兼而有之)中,存在一个公开的研究问题


总之,目前还没有已知的安全(内存和功能)杀死线程的方法。

朋友们,这是可能的。使用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!"),
    }
}
要点:

在游乐场:


UPD:我已经创建了
线程控制
板条箱,它实现了这种方法:

我认为Arc可以用来解决这个问题
如果线程退出,则引用计数器将减少一个

如果线程从未发送消息,但
try_recv产生了错误,我们是否可以断定线程已经终止?不一定;线程可以提前删除其发送方(例如,使用
drop(sender);
let\uux0=sender;
)。现在,如果这些是唯一的假阳性情况,那么我猜线程可能会接收
\u sender
作为参数,并且永远不会使用它。这样一来,
\u发送方
将充当生命线。。除非编译器决定立即解除分配它?否,
\u sender
是一个有效的变量名(与
\u
不同),因此析构函数将在该变量超出范围时运行,而不是更早,除非您自己移出该变量。任何级别的优化都不会改变这一点。太好了!因此,我可以检查子线程是否在没有阻塞的情况下退出,并且只使用
std
。诀窍是
let(rx,tx)=mpsc::channel()
,将
tx
侧移到子线程,并定期检查
rx。尝试_recv()
,直到它产生。就线程而言,它需要接收
\u tx
,并承诺不使用它。我能想到的唯一缺点是,如果子线程是由其他人编写的,我无法强制执行它不会过早地删除
\u tx
:\