Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should std::async respect thrown errors?

Tags:

c++

c++17

I'm trying to understand how exceptions are handled asynchronously -- I have a webserver that contains a lambda handler for processing requests (uWebsockets) and it keeps crashing. To simulate the scenario I used std::async

void call(function<void()> fn) {
  std::async([&fn]{
    fn();
  });
}

int main() {
  try {
    call([](){
      throw std::runtime_error("Oops");
    });
  } catch (std::runtime_error &e) {
    cout<<"Caught the error"<<endl;
  }
  std::this_thread::sleep_for(std::chrono::milliseconds(100000));
} 

It seems that running the function inside std::async causes the runtime error to never execute ... the program just exits as if nothing happened... why is this the case?

like image 894
user491880 Avatar asked May 02 '26 08:05

user491880


1 Answers

Let's take this step by step. Let's start with the very definition of what std::async does. It:

runs the function f asynchronously (potentially in a separate thread

The word "potentially" is a distraction here, but the point is that a different execution thread is going to be involved here. For all practical reasons, the function getting std::async-ed can, and on modern C++ implementations, it will run in a new execution thread.

The very reason for having different execution threads, in the first place, is that they are completely independent of their parent execution thread. Different execution threads must properly implement sequencing operations in order to mutually exchange information between themselves, in some form or fashion.

  try {

  } catch (std::runtime_error &e) {
    cout<<"Caught the error"<<endl;
  }

The concept of exceptions, and how try and catch relate to them, is introduced in your average C++ textbook by explaining how try/catch will catch exceptions that occur inside the try/catch block. Once execution leaves the try/catch block, exception handling is no longer in effect, and no exception will be caught (unless execution is inside another try/catch block).

It may or may not be immediately clear that combining the concepts of execution threads and this typical explanation of exception handling, you must reach the inevitable conclusion that you can only catch exceptions thrown from the same execution thread.

Additionally, in the shown code, there's absolutely nothing that even guarantees that the original execution thread will still be inside the try/catch block when the exception in the other execution thread gets thrown. In fact, it is more likely than not that the parent execution thread has left the original try/catch block and it's sleep_for-ing, when the exception gets thrown. You cannot catch exceptions any more, after leaving the try/catch block.

But even if the original execution thread is still inside the try/catch block this won't make any difference, because thrown exceptions can only be caught by the same execution thread, but the function that gets executed by std::async will be running in a completely different execution thread.

Edit:

std::async([&fn]{

This captures fn by reference. fn is a function parameter that goes out of scope and gets destroyed when the function returns, but there's no guarantee that the new execution thread will reference it before it does. This is immaterial, for the purposes of the mechanics of exception handling (and to how std::async itself handles thrown exceptions), but this needs to be fixed nevertheless.

like image 166
Sam Varshavchik Avatar answered May 04 '26 20:05

Sam Varshavchik



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!