What is the best way to propagate errors out from a separate thread (eg. start block, Proc::Async, or sub containing these). Simply wrapping the code that spins off a new thread in a try/CATCH block does not work, and using await only works depending on the return value of the sub routine (ie. a sub returning self will not work with the await approach).
To catch the exception in the caller thread we maintain a separate variable exc, which is set to the exception raised when the called thread raises an exception. This exc is finally checked in the join () method and if is not None, then join simply raises the same exception.
For invoking a thread, the caller thread creates a thread object and calls the start method on it. Once the join method is called, that initiates its execution and executes the run method of the class object.
Thus, the caught exception is raised in the caller thread, as join returns in the caller thread (Here The Main Thread) and is thus handled correspondingly. Attention geek! Strengthen your foundations with the Python Programming Foundation Course and learn the basics.
If you spawn a future on a new thread using std::async(std::launch::async, ...); and that future’s worker throws an exception, when you later call get() on the future it will emit that exception.
Use await
.
For example, replace these three lines in your code:
foo;
bar;
baz;
with:
await foo, bar, baz;
Following the convention used in Go to pass errors out of go routines using channels, I found the same approach to work in Raku. One can use a Channel to send errors out of the asynchronous code to be handled by the main thread.
Example:
my $errors = Channel.new;
my $err-supply = $errors.Supply;
$err-supply.tap(-> $e {say "handle error: $e"});
start {
die "something went horribly wrong";
CATCH {
default {
$errors.send($_);
}
}
}
sleep 1;
Theoretically, that code should die:
As of the 6.d version of the language, start statement prefix used in sink context will automatically attach an exceptions handler. If an exception occurs in the given code, it will be printed and the program will then exit, like if it were thrown without any start statement prefixes involved.
use v6.c;
start { die }; sleep ⅓; say "hello"; # OUTPUT: «hello»
use v6.d;
start { die }; sleep ⅓; say "hello";
# OUTPUT:
# Unhandled exception in code scheduled on thread 4
# Died
# in block at -e line 1
In this case it's a weird situation because you're not sinking the promise (you're returning it), but eventually you sink it because you're running it in void context.
The same documentation gives you the solution: don't sink the context:
# Don't sink it:
my $ = start { die }; sleep ⅓; say "hello"; # OUTPUT: «hello»
# Catch yourself:
start { die; CATCH { default { say "caught" } } };
sleep ⅓;
say "hello";
Since your program does not die, I would say you're in the second situation. For some reason, it's not sunk. But whatever is the situation, the solution is the same: you need to catch the exception inside the same code block.
Solution: await
the promise (which will not sink it) or assign it to some variable, so that the surrounding code dies too. But responding your OP, no, you can't catch an exception from another thread, same way you can't catch an exception from another block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With