I have a program that needs to propagate exceptions from any uncaught thread to the main thread, so that it may provide the user with information about why it failed and shut down safely. My InterThreadException
handler seems to work but only when the thread that throws an exception is spawned directly by the main thread.
The InterTheadException
handler is invoked correctly in all cases, being signaled that an exception is propagated by having an exception pointer passed to it, and the main thread receives the notification that it has received a new exception, but the call to std::rethrow_exception
on the exception pointer simply fails and seemingly does nothing. I have tested throwing the exact same exception from these two different threads, and the problem seems to persist no matter what I throw.
I suspect I have a fundamental misunderstanding on how one is supposed to use exception pointers, but I'm not sure.
Here is my implementation of the InterThreadExceptionHandler
.
class InterThreadExceptionHandler : NonCopyable
{
public:
InterThreadExceptionHandler();
~InterThreadExceptionHandler();
//
// Sends an exception into this handler, informing it that
//this exception has been caught
// and may be propagated to another thread
//
void sendException(std::exception_ptr exception);
//
// Freezes the calling thread until an exception has been sent,
//then rethrows said exception
//
void waitForException();
private:
std::vector<std::exception_ptr> sentExceptions;
std::mutex sentExceptionsMutex;
Semaphore sentExceptionsCounter;
};
InterThreadExceptionHandler::InterThreadExceptionHandler()
{
}
InterThreadExceptionHandler::~InterThreadExceptionHandler()
{
}
void InterThreadExceptionHandler::sendException(std::exception_ptr exception)
{
ScopedLock lock(this->sentExceptionsMutex);
this->sentExceptions.push_back(exception);
this->sentExceptionsCounter.give();
}
void InterThreadExceptionHandler::waitForException()
{
this->sentExceptionsCounter.take();
ScopedLock lock(this->sentExceptionsMutex);
assert( this->sentExceptions.size() > 0 );
std::exception_ptr e = this->sentExceptions[0];
this->sentExceptions.erase(this->sentExceptions.begin());
if (e == std::exception_ptr())
{
throw std::exception("Invalid exception propagated!");
}
std::rethrow_exception(e);
}