User Tools

Site Tools


c:c_threads:troubleshooting:program_crashes:not_handling_exceptions_in_background_threads

C - C++ Threads - Troubleshooting - Program Crashes - Not handling exceptions in background threads

Exceptions thrown in one thread cannot be caught in another thread.

If a function executes in a separate thread forked from main and exception from this thread cannot be caught in the main thread.


Example

#include<iostream>
#include<thread>
#include<exception>
#include<stdexcept>
 
static std::exception_ptr teptr = nullptr;
 
void HelloWorld()
{
  throw std::runtime_error("Catch me in MAIN");
}
 
 
int main()
{
  try
  {
    std::thread t1(HelloWorld);
    t1.join();
  }
  catch (const std::exception &ex)
  {
    std::cout << "Thread exited with exception: " << ex.what() << "\n";
  }
  return 0;
}

NOTE: The above program will crash and the catch block in main() will do nothing to handle the exception thrown thread t1.

The solution is to use the C++11 feature std::exception_ptr to capture an exception thrown in a background thread.

Here are the steps you need to do:

  • Create a global instance of std::exception_ptr initialized to nullptr
  • Inside the function that executes in the forked thread, catch any exception and set the std::current_exception() to the std::exception_ptr in step 1.
  • Inside the main thread, check if the global exception pointer is set.
  • If yes, use std::rethrow_exception(exception_ptr p) to rethrow the exception referenced by exception_ptr parameter.

Rethrowing the referenced exception does not have to be done in the same thread that generated the referenced exception in the first place, which makes this feature perfectly suited for handling exceptions across different threads.


Resolution

#include<iostream>
#include<thread>
#include<exception>
#include<stdexcept>
 
static std::exception_ptr globalExceptionPtr = nullptr;
 
void HelloWorld()
{
  try
  {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    throw std::runtime_error("Catch me in MAIN");
  }
  catch (...)
  {
    // Set the global exception pointer in case of an exception.
    globalExceptionPtr = std::current_exception();
  }
}
 
 
int main()
{
  std::thread t1(HelloWorld);
  t1.join();
  if (globalExceptionPtr)
  {
    try
    {
      std::rethrow_exception(globalExceptionPtr);
    }
    catch (const std::exception &ex)
    {
      std::cout << "Thread exited with exception: " << ex.what() << "\n";
    }
  }
  return 0;
}
c/c_threads/troubleshooting/program_crashes/not_handling_exceptions_in_background_threads.txt · Last modified: 2021/06/09 12:17 by peter

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki