Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

rust - Recovering from `panic!` in another thread

I know that in Rust there is no try/catch, and you can't throw a rolling save from the thread that is currently panicking.

I know you should not create and handle errors like this. This is just for example's sake.

However, I am wondering what the best way to recover from a panic is. This is what I have now:

use std::thread;

fn main() {
    println!("Hello, world!");

    let h = thread::spawn(|| {
        thread::sleep_ms(1000);
        panic!("boom");
    });

    let r = h.join();
    match r {
        Ok(r) => println!("All is well! {:?}", r),
        Err(e) => println!("Got an error! {:?}", e)
    }

    println!("Exiting main!");
}

Is there a better way to handle errors from other threads? Is there a way to capture the message of the panic? This seems to only tell me that the error is of type Any. Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Putting aside "you should be using Result where possible," yes, this is basically how you catch a panic in Rust. Keep in mind that "recover" is perhaps not the best way of phrasing this in Rust. You don't really recover from panics in Rust, you isolate them, then detect them. There is no On Error Resume Next :P.

That said, there are two things to add to your example. First is how to get at the panic message. The key observation is that Any, in order to be used, must be explicitly downcast to the exact, concrete type it contains. In this case, since the panic message is a &'static str, you need to downcast to that.

The second thing is that there is a new API in nightly called catch_panic that lets you isolate a panic without having to start a thread. That said, it comes with the same restrictions as spawning a new thread: you cannot pass a non-'static reference across the isolation boundary. Note that this is an unstable addition; there are no guarantees about stability yet, and you'll need a nightly compiler to access it.

Here is an example which shows both of those. You can also run this on the Rust Playpen.

#![feature(catch_panic)]

use std::thread;

fn main() {
    println!("Hello, world!");

    let h = thread::spawn(|| {
        thread::sleep_ms(500);
        panic!("boom");
    });

    let r = h.join();
    handle(r);

    let r = thread::catch_panic(|| {
        thread::sleep_ms(500);
        panic!(String::from("boom again!"));
    });

    handle(r);

    println!("Exiting main!");
}

fn handle(r: thread::Result<()>) {
    match r {
        Ok(r) => println!("All is well! {:?}", r),
        Err(e) => {
            if let Some(e) = e.downcast_ref::<&'static str>() {
                println!("Got an error: {}", e);
            } else {
                println!("Got an unknown error: {:?}", e);
            }
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...