2017-03-07 21 views
5

Biorąc pod uwagę następujący kod źródłowystd :: futures i wyjątek

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

} 

Spodziewam się, że program będzie odpowiedź z Valid: 0. W tym przypadku używa się g ++ 6.2.0. Jednakże, używając MS VS2015 Wersja 14.0.25431.01 Update 3 odpowiedź jest Valid: 1. Stan przyszłości nie jest nieważny, po tym, jak wyjątek został przeniesiony do głównego wątku. Czy jest to błąd, czy też mam tu do czynienia z niezdefiniowanym zachowaniem?

Odpowiedz

1

I wydaje się, że to błąd.

Zgodnie z std::future::get documentation, valid() powinien zwrócić false po zakończeniu połączenia z numerem get.

Wszelkie wspólne państwo jest zwolniony. valid() jest false po wywołaniu tej metody.

Kopanie trochę do realizacji VC++ z get, istnieje bug tam:

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

zasadzie _Retreived powinien również być ustawiony true jeśli _Exception posiada exception_ptr. do czasu rzucania zmienna ta nigdy nie jest ustawiona. wydaje się, że gdy testowałem go, nie przetestować gotowy przyszłości tylko za brak gotowości przyszłości, ponieważ ten ostatni nie pokaże ten błąd.

+0

Czy istnieje obejście? Po usunięciu instrukcji wait_for działa ona zgodnie z oczekiwaniami, ale w moim kodzie produkcyjnym potrzebuję przepływu programu podobnego do źródła próbki. – IcePic

+0

@IcePic może używać 'współbieżności :: task' zamiast. pod VC++, 'std :: async' jest tak czy inaczej cienkim opakowaniem zadań. –