Clean process exit when panic occur

There are multiple sub threads (created inside functions called by the main thread). These secondary threads panic on errors. If even one thread among them panics, the program must terminate.

Now, consider the situation in which I have the 'Main Thread', then 'Thread A' and then 'Thread B'.
If Thread B panics, how can I panic also Thread A ( in order to freed its resources ) and finally permit to the Main Thread to exit the process using std::process::exit(1)?

use std::thread;
use std::thread::JoinHandle;
use std::time::Duration;

fn main() {
    let t1 = function_a();
    let t2 = function_b();
    t1.join().expect("MAIN PANICKED (A)");
    t2.join().expect("MAIN PANICKED (B)");
    println!("MAIN THREAD");
}

fn function_a() -> JoinHandle<()> {
    let h = thread::spawn(|| {
        let mut i = 0;
        while i < 10 {
            println!("Thread A printing {}", i);
            i += 1;
        }
    });

    h
}

fn function_b() -> JoinHandle<()> {
    let h = thread::spawn(|| {
        for i in 0..5 {
            println!("THREAD_B printing : {}", i);
        }
        panic!("B panicked!");
    });

    h
}
1 Like

Generally speaking you don't need to do things like free memory or close files if you're about to exit the process.

If you're trying to ensure a file you're writing is always written to completely in thread A even if thread B panics, you may want to consider using something like SQLite where the data format can provide some extra guarantees about the file not being corrupted by the process getting killed. Even if you implement something to notify thread A it needs to clean up, the OS can still kill your process in a way that prevents any clean up from being run.

All that being said, if you just want to have threads be notified that they should clean up, you can use catch_unwind inside each thread::spawn closure to temporarily stop an unwinding panic, and use an Arc<AtomicBool> to let other threads know a panic occured and they should start cleaning up. After that you can call resume_unwind to have the panic continue and cause the thread to exit.

The threads will need to check the AtomicBool periodically to notice that they need to clean up though, there's no way to interrupt a thread from the outside.

Also note that it's possible for a binary crate to set panics to abort instead of unwind, in which case you can't catch the panic at all, your program will simply exit at time of the panic.

And thus, you shouldn't use panics for error handling. You should really use Result for that. I mean, the very signature of ThreadHandle::join() suggests that. It returns a Result which you can match on or bubble using ?, etc.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.