In Rust, a panic terminates the current thread but is not sent back to the main thread. The solution we are told is to use join
. However, this blocks the currently executing thread. So if my main thread spawns 2 threads, I cannot join both of them and immediately get a panic back.
let jh1 = thread::spawn(|| { println!("thread 1"); sleep(1000000); };
let jh2 = thread::spawn(|| { panic!("thread 2") };
In the above, if I join on thread 1 and then on thread 2 I will be waiting for 1 before ever receiving a panic from either thread
Although in some cases I desire the current behavior, my goal is to default to Go's behavior where I can spawn a thread and have it panic on that thread and then immediately end the main thread. (The Go specification also documents a protect
function, so it is easy to achieve Rust behavior in Go).
This you can achieve with the unstable
std::panic::set_handler()
. You can set a handler which prints the panic info and then exits the whole process, something like this:Try commenting
set_handler()
out, and you'll see thatprintln!()
line gets executed.However, this approach, due to
process::exit()
usage, will not allow resources allocated by other threads to be freed. In fact, I'm not sure that Go runtime allows this as well; it is likely that it uses the same approach with aborting the process.I tried to force my code to stop processing when any of threads panicked. The only more-or-less clear solution without using unstable features was to use
Drop
trait implemented on some struct. This can lead to a resource leak, but in my scenario I'm ok with this.No matter how
b = PoisonPill
leaves it's scope, normal or afterpanic!
, itsDrop
method kicks in. You can distinguish if the caller panicked usingthread::panicking
and take some action — in my case killing the process.