6

给定以下源代码

#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;
    }

}

我希望,该程序将响应Valid: 0。使用 g++ 6.2.0 就是这种情况。但是,使用 MS VS2015 版本 14.0.25431.01 更新 3 的响应是Valid: 1. 在异常传播到主线程之后,未来的状态不会失效。这是一个错误还是我在这里遇到了未定义的行为?

4

1 回答 1

3

我似乎是一个错误。

根据std::future::get文档,调用后valid()应该返回.falseget

任何共享状态都会被释放。valid()false在调用此方法之后。

深入研究 VC++ 实现get,那里有一个错误:

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);
        }

基本上,_Retreived也应该设置为trueif_Exception持有一个exception_ptr. 到投掷时,这个变量永远不会被设置。似乎当他们测试它时,他们没有测试一个准备好的未来,只测试非准备好的未来,因为后者不会显示这个错误。

于 2017-03-07T12:42:12.783 回答