Should std::async respect thrown errors?

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?

>Solution :

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.

Leave a Reply