在Rust中,紧急情况会终止当前线程,但不会发送回主线程。我们被告知的解决方案是使用join。但是,这会阻塞当前正在执行的线程。因此,如果我的主线程产生了2个线程,那么我将无法同时加入这两个线程并立即感到恐慌。
let jh1 = thread::spawn(|| { println!("thread 1"); sleep(1000000); };
let jh2 = thread::spawn(|| { panic!("thread 2") };
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,如果我在线程1上然后在线程2上加入,我将在等待1之前从任一线程收到恐慌
尽管在某些情况下我希望当前的行为,但我的目标是默认使用Go的行为,在该行为中我可以生成线程并使它在该线程上处于紧急状态,然后立即结束主线程。(Go规范还记录了一个protect功能,因此很容易在Go中实现Rust行为)。
Vla*_*eev 13
针对 Rust 1.10+ 更新,请参阅答案的先前版本的修订历史
好点,在 go 中,主线程没有解开,程序只是崩溃,但报告了最初的恐慌。这实际上是我想要的行为(尽管理想情况下资源会在任何地方得到正确清理)。
这可以通过最近稳定的std::panic::set_hook()功能实现。有了它,你可以设置一个钩子来打印恐慌信息,然后退出整个过程,就像这样:
use std::thread;
use std::panic;
use std::process;
fn main() {
// take_hook() returns the default hook in case when a custom one is not set
let orig_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| {
// invoke the default handler and exit the process
orig_hook(panic_info);
process::exit(1);
}));
thread::spawn(move || {
panic!("something bad happened");
}).join();
// this line won't ever be invoked because of process::exit()
println!("Won't be printed");
}
Run Code Online (Sandbox Code Playgroud)
尝试对set_hook()调用进行注释,您将看到该println!()行已被执行。
但是,由于使用了 ,这种方法process::exit()将不允许释放其他线程分配的资源。事实上,我不确定 Go 运行时是否也允许这样做;它很可能使用与中止过程相同的方法。
小智 9
当任何线程恐慌时,我试图强制我的代码停止处理。不使用不稳定特性的唯一或多或少清晰的解决方案是使用Drop在某些结构上实现的特征。这可能会导致资源泄漏,但在我的情况下,我对此没有意见。
use std::process;
use std::thread;
use std::time::Duration;
static THREAD_ERROR_CODE: i32 = 0x1;
static NUM_THREADS: u32 = 17;
static PROBE_SLEEP_MILLIS: u64 = 500;
struct PoisonPill;
impl Drop for PoisonPill {
fn drop(&mut self) {
if thread::panicking() {
println!("dropped while unwinding");
process::exit(THREAD_ERROR_CODE);
}
}
}
fn main() {
let mut thread_handles = vec![];
for i in 0..NUM_THREADS {
thread_handles.push(thread::spawn(move || {
let b = PoisonPill;
thread::sleep(Duration::from_millis(PROBE_SLEEP_MILLIS));
if i % 2 == 0 {
println!("kill {}", i);
panic!();
}
println!("this is thread number {}", i);
}));
}
for handle in thread_handles {
let _ = handle.join();
}
}
Run Code Online (Sandbox Code Playgroud)
无论如何b = PoisonPill离开它的范围, normal 或 after panic!,它的Drop方法都会启动。您可以区分调用者是否使用恐慌thread::panicking并采取一些行动 - 在我的情况下杀死进程。
看起来在任何线程中出现恐慌时退出整个过程现在(rust 1.62)就像将其添加到 Cargo.toml 一样简单:
[profile.release]
panic = 'abort'
[profile.dev]
panic = 'abort'
Run Code Online (Sandbox Code Playgroud)
线程中的恐慌看起来像这样,退出代码为 134:
thread '<unnamed>' panicked at 'panic in thread', src/main.rs:5:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Aborted (core dumped)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1839 次 |
| 最近记录: |