Butch Lewis
Butch Lewis

Reputation: 21

std::thread, thowing an exception in thread causes abort error in Visual C++

I have been experimenting with std:thread. I am using a binary expression tree for the standard arithmetic operations. I am creating a thread to perform the calculations and want to check for divide by zero. When the thread is started with std::async, the exception is thrown from the worker thread and caught just fine in the main thread. When I start the thread with std::thread, when the exception is thrown, I get a run-time error, abort(). Any insights as to why it works with std::async but notstd::thread`?

// Declaration in the Expression.h file
public:
    static long double __stdcall ThreadStaticEntryPoint(void * pThis);


long double __stdcall Expression::ThreadStaticEntryPoint(void * pThis)
{
    long double calc;

    Expression* pthrdThis = (Expression*)pThis;
    calc = pthrdThis->Calculate();

    return calc;
}

case 6:
    try {
    // Below works when encountering divide by zero.
    // The thrown exception is caught correctly  
    // Launch thread using the this pointer

        std::future<long double> fu = std::async(std::launch::async,
            ThreadStaticEntryPoint, this);
        calc = fu.get();

        // When Creating a thread as below and I throw a divide by zero 
    // exception I get an error in visual C++. Below does not work:

        //std::thread t1(&Expresson::Calculate, this);
        //t1.join();

        // Below works fine also
        //calc = Calculate();
    }
    catch (runtime_error &r)
    {
            ShowMessage("LoadMenu() Caught exception calling Calculate()");
            ShowMessage(r.what());
    }
    catch (...) {
            ShowMessage("Exception caught");
        }

long double Expresson::Calculate()
{
    Expression *e;
    long double calc = 0;

    e = rep->GetExpression();
    if (e == NULL)
    {
        ShowMessage("Main Expression " + to_string(rep->GetMainExpIndex()) + " is NULL. ");
        return 0;
    }

    calc = e->Calculate()

    return calc;
}

//************************************************************
// Calculate - Calculates Lval / Rval, returns result
//************************************************************
long double Divide::Calculate()
{
    Expression* lop = this->getLOperand();
    Expression* rop = this->getROperand();
    long double Lval = 0, Rval = 0;
    long double result = 0;

    if (lop == NULL || rop == NULL)
        return result;

    Lval = lop->Calculate();
    Rval = rop->Calculate();
    //result = divides<long double>()(Lval, Rval);
    // The throw error below causes the error
    if (Rval == 0)
        throw runtime_error("DivExp::Calculate() - Divide by zero exception occured. Rval = 0");

    result = Lval / Rval;

    return result;

}

Upvotes: 2

Views: 2461

Answers (1)

Loki Astari
Loki Astari

Reputation: 264669

That is the expected behavior:

See the std::thread documentation

Threads begin execution immediately upon construction of the associated thread object (pending any OS scheduling delays), starting at the top-level function provided as a constructor argument. The return value of the top-level function is ignored and if it terminates by throwing an exception, std::terminate is called.

See the std::async documentation

then async executes the function f on a new thread of execution (with all thread-locals initialized) as if spawned by std::thread(f, args...), except that if the function f returns a value or throws an exception, it is stored in the shared state accessible through the std::future that async returns to the caller.

Upvotes: 6

Related Questions