JoinHandle
,这个对象很适合用来…等待(一个阻塞操作),但除此之外没什么其他用处。如何检查子线程是否已经退出(也就是说,JoinHandle.join()
不会阻塞)?如果您知道如何终止一个子线程则可以获得额外的积分。我想通过创建通道,向子进程发送一些内容,并捕获错误来实现此目的,但这似乎是不必要的复杂性和开销。
JoinHandle
,这个对象很适合用来…等待(一个阻塞操作),但除此之外没什么其他用处。如何检查子线程是否已经退出(也就是说,JoinHandle.join()
不会阻塞)?如果您知道如何终止一个子线程则可以获得额外的积分。Receiver
具有非阻塞的 try_recv
方法。当 try_recv
收到消息时,您可以使用 JoinHandle
上的 join()
来检索线程的结果。朋友们,这是可能的。使用Rust会在结束或崩溃时丢弃的引用计数器。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
更新: 我创建了thread-control
包来实现这个方法: https://github.com/DenisKolodin/thread-control
简短回答是目前还不可能。但这并不是真正需要解决的问题。
如果你知道如何终止一个子线程,就可以得到额外的加分。
千万不要
即使在支持终止线程的语言中 (比如Java),也建议不要这样做。
线程的执行通常会编码显示的交互点,并且经常有隐含的假设认为不会发生其他任何干扰。
最极端的例子当然是资源:天真的 "终止" 方法将停止执行线程;这意味着不释放任何资源。您可以考虑内存,这是您最不用担心的。相反,想象一下所有没有解锁并将在以后创建死锁的 Mutex
...
另一种选择是向线程注入 panic
,从而导致展开。但是,您不能 只是在任何时间点开始展开!程序必须定义 安全点,在这些点注入 panic
将被保证是安全的(在任何其他点注入它都意味着潜在地破坏共享对象);如何定义这样的安全点并在其中注入 panic
是本机语言中一个开放的研究问题,特别是那些在系统上执行 W^X
(内存页面仅为可写或可执行,但绝不是两者兼备)。
总之,目前没有已知的安全方法(无论从内存还是从功能上)可以杀死一个线程。
is_finished
方法。
https://doc.rust-lang.org/stable/std/thread/struct.JoinHandle.html#method.is_finished
我认为Arc可以用来解决这个问题,如果线程退出,则引用计数器将减少一个。
try_recv
返回Disconnected
,那我们可以得出结论该线程已终止吗? - iago-litodrop(sender);
或let _ = sender;
)。 - Francis Gagné_sender
作为参数并且从未使用它。这样,_sender
就会像生命线一样起作用...除非编译器决定立即释放它? - iago-lito_sender
是一个有效的变量名(不像_
),所以析构函数将在该变量超出作用域时运行,除非你自己移出该变量。任何优化级别都无法改变这一点。 - Francis Gagnéstd
而不会阻塞来检查子线程是否已退出。诀窍是let (rx, tx) = mpsc::channel();
,将tx
移动到子线程中,并定期检查rx.try_recv()
,直到它产生Err(Disconnected)
。在其侧面,线程需要接收_tx
并承诺根本不使用它。我唯一能想到的缺点是,如果其他人编写了_tx
,我无法强制执行子线程不会提前丢弃_tx
。 - iago-lito