Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is std::exception_ptr thread safe?

I have a worker thread that is constantly running, created & managed through a std::thread. At the top level of my worker thread, I have a try/catch block with a while loop inside it. If an exception leaks through to the top level of the thread, I catch it and store it in a std::exception_ptr, which is a member of the class that also owns the non-static thread function:

// In class header (inside class declaration)
std::exception_ptr m_threadException;

// In class CPP file
void MyClass::MyThreadFunction()
{
    try {
        while (true) {
            // Do thread stuff
        }
    }
    catch (std::exception const& e) {
        m_threadException = std::current_exception();
    }
}

Once the thread dies due to this kind of exception, my class (which is also primarily used by the main thread) doesn't know it yet. My plan was to add thread checkpoints to the start of all the class's main functions, like so:

void MyClass::SomethingMainThreadCalls()
{
    if (m_threadException) {
        std::rethrow_exception(m_threadException);
        m_threadException = nullptr; // Somehow reset it back to null; not sure if this will work
    }

    // Do normal function stuff
}

Assuming this is even a good idea, there's a possible race condition between when my main thread is checking if the exception_ptr is null (when calling SomethingMainThreadCalls()) and when the worker thread assigns to it. I haven't found any information (haven't checked the C++11 draft yet) about whether or not this is inherently thread safe (guaranteed by the standard) or if I am responsible for thread synchronization in this case.

If the latter, is using std::atomic a good idea to keep it simple? Example:

std::atomic<std::exception_ptr> m_threadException;

Something like that? Hoping that the answer to my question also involves some good recommendations and information on best practice here. Thanks in advance.

like image 246
void.pointer Avatar asked Dec 22 '16 17:12

void.pointer


3 Answers

There is no special statement about exception_ptr with regards to its thread safety in the standard. As such, it provides the default standard guarantee: accessing separate instances are fine, accessing the same instance is not.

I would suggest using atomic<bool> instead (if for no other reason than that exception_ptr is not trivially copyable and therefore can't be put in an atomic<T>) to let the other code know that the exception_ptr has been set. You'll be fine so long as:

  1. You set m_threadException before setting the flag
  2. You read m_threadException after checking the flag
  3. You use the appropriate load/store memory orders to set/check the flag. The defaults are fine
  4. You only write m_threadException exactly once.
like image 74
Nicol Bolas Avatar answered Nov 09 '22 02:11

Nicol Bolas


The standard doesn't specify what is the implementation of std::exception_ptr, so the thread safeness of std::exception_ptr is also unspecified.

just wrap the exception pointer with some lock and the code will be fine.

like image 31
David Haim Avatar answered Nov 09 '22 01:11

David Haim


Just tried to do this, but std::atomic requires a trivially copyable type, std::exception_ptr is not. You should get compilation error as I do (when using MSVC VS2019, C++14).

like image 2
Andrey Borisovich Avatar answered Nov 09 '22 02:11

Andrey Borisovich