2017-03-07 17 views
5

次のソースコードのstd ::先物および例外

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

} 

を考えます。 g ++ 6.2.0を使用しています。しかし、MS VS2015バージョン14.0.25431.01 Update 3を使用すると、応答はValid: 1になります。将来の状態は、例外がメインスレッドに伝播された後、無効にされません。これはバグですか、私はここで未定義の振る舞いをしていますか?

答えて

1

私はバグのようです。

std::future::get documentationによれば、getを呼び出した後にvalid()falseを返す必要があります。

すべての共有状態が解除されます。 valid()falseです。 getのVC++の実装にビットを掘り

は、バグがそこにある:_Exceptionexception_ptrを保持している場合

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

は基本的に、_Retreivedtrueに設定する必要があります。スローするまでに、この変数は設定されません。彼らはテストしたときに、準備ができている未来のためにテストしなかったようです。 は、このバグが表示されないため、準備ができていない将来のみテストされます。

+0

回避策はありますか?私はwait_forステートメントを削除すると、期待どおりに動作しますが、私のプロダクションコードでは、サンプルソースに似たプログラムフローが必要です。 – IcePic

+0

@IcePicは代わりに 'concurrency :: task'を使うかもしれません。 VC++の下では、 'std :: async'はとにかくタスクを囲む薄いラッパーです。 –

関連する問題