Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::futures and exception

Given the following source code

#include <thread>
#include <future>
#include <iostream>
#include <string>
#include <chrono>

int main() {

    auto task = std::async(std::launch::async, [] {       
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        throw std::runtime_error("error");
    });


    try {
        while (task.wait_for(std::chrono::seconds(0)) !=std::future_status::ready)
        {
            std::cout << "Not ready: " << std::endl;
        }
        task.get();
    }
    catch (const std::exception& e)
    {
        std::cout << "Valid: " << task.valid() << std::endl;
    }

}

I would expect, that the program will response with Valid: 0. Using g++ 6.2.0 this is the case. However, using MS VS2015 Version 14.0.25431.01 Update 3 the response is Valid: 1. The state of the future is not invalidaded, after the exception was propagated to the main thread. Is this a bug or am i running into undefined behaviour here?

like image 646
IcePic Avatar asked Mar 07 '17 12:03

IcePic


1 Answers

I appears to be a bug.

According to std::future::get documentation , valid() should return false after a call to get.

Any shared state is released. valid() is false after a call to this method.

Digging a bit into VC++ implementation of get, there is a bug there:

virtual _Ty& _Get_value(bool _Get_only_once)
        {   // return the stored result or throw stored exception
        unique_lock<mutex> _Lock(_Mtx);
        if (_Get_only_once && _Retrieved)
            _Throw_future_error(
                make_error_code(future_errc::future_already_retrieved));
        if (_Exception)
            _Rethrow_future_exception(_Exception);
        _Retrieved = true;
        _Maybe_run_deferred_function(_Lock);
        while (!_Ready)
            _Cond.wait(_Lock);
        if (_Exception)
            _Rethrow_future_exception(_Exception);
        return (_Result);
        }

basically, _Retreived should also be set to true if _Exception holds an exception_ptr. by the time of throwing, this variable is never set. it appears that when they tested it, they didn't test for a ready future, only for non ready future, because the latter will not show this bug.

like image 143
David Haim Avatar answered Oct 20 '22 02:10

David Haim