2017-09-15 23 views
6

Następujący kod ulega awarii w losowych odstępach czasu po utworzeniu z MSVC pod trybem Debug, w przeciwieństwie do trybu Release.Awaria podczas przypisywania do std :: future w trybie debugowania MSVC

#include <future> 

using namespace std; 

int main() { 
    auto l = [](){}; 
    auto f = async(launch::async, l); 

    for (int i = 0; i < 1000000; ++i) 
     f = async(launch::async, l); 
} 

na konsoli mówi:

f: \ dd \ vctools \ crt \ crtw32 \ stdcpp \ Thr \ mutex.c (51) Muteks zniszczeniu podczas zajęty

Pełny stos wywoławczy to: https://pastebin.com/0g2ZF5C1

Oczywiście jest to po prostu próba stresu, ale czy robię coś zupełnie głupiego? Wydaje mi się, że to dobrze, aby przypisać nowe zadanie do istniejącej przyszłości, jak to powiedział, że operator=:

prasowe jakikolwiek wspólny stan i przenieść-przypisuje zawartość innych do * to

(Z powodu http://en.cppreference.com/w/cpp/thread/future/operator%3D).

Czy to błąd w środowisku wykonawczym MSVC?

Co ciekawe, program zatrzymuje upaść, jeśli ręcznie zadzwonić wait() przed przypisaniem, tworząc w ten sposób pętlę w:

for (int i = 0; i < 1000000; ++i) { 
    f.wait(); 
    f = async(launch::async, l); 
} 

Czy nie operator= sam powinien zadzwonić wait?

Tło:

_MSC_VER równa 1911

Kod został zbudowany z pomocą:

Microsoft Visual Studio Community 2017 Preview(2) 
Version 15.4.0 Preview 2.0 

właśnie otworzył nowy C++ projektu.

+0

Przydałaby się dokładna wersja pliku msvc i kompilatora. – Yakk

+0

Po prostu zgadnij: Czasami prawdopodobnie "l" jest nadal wykonywane podczas próby ponownego przypisania f.Prawdopodobnie obciążenie związane z tworzeniem lambda podczas debugowania jest znacznie większe w porównaniu z obciążeniem pozostałej wersji kodu debugowania. To może wyjaśnić, że dzieje się tak tylko w wersji do debugowania. –

+0

@Yakk Pewnie, zredagowałem to pytanie. –

Odpowiedz

1

Czy nie operator= sam powinien zadzwonić wait?

Nie wiem, czy to jest powinien, ale pobieżny rzut oka na realizację MSVC15.3.4 z <future> wydaje się silnie sugerują, że nie.

//User Code 
future f = /*...*/; 
f = /*...*/; //(1) 
//MSVC Code 
future& operator=(future&& _Right) _NOEXCEPT //(1) 
    { // assign from rvalue future object 
    _Mybase::operator=(_STD move(_Right)); //(2) 
    return (*this); 
    } 
_State_manager& operator=(_State_manager&& _Other) //(2) 
    { // assign from rvalue _Other 
    _Move_from(_Other); //(3) 
    return (*this); 
    } 
void _Move_from(_State_manager& _Other) //(3) 
    { // move stored associated asynchronous state object from _Other 
    if (this != _STD addressof(_Other)) 
     { // different, move 
     if (_Assoc_state) 
      _Assoc_state->_Release(); //(4) 
     _Assoc_state = _Other._Assoc_state; 
     _Other._Assoc_state = 0; 
     _Get_only_once = _Other._Get_only_once; 
     } 
    } 
void _Release() //(4) 
    { // decrement reference count and destroy when zero 
    if (_MT_DECR(_Refs) == 0) 
     _Delete_this(); //(5) 
    } 
void _Delete_this() //(5) 
    { // delete this object 
    if (_Deleter) 
     _Deleter->_Delete(this); //External Code 
    else 
     delete this; 
    } 

Widząc jak wywoływanie wait pomaga zsynchronizować rzeczy i upewnić się, że obiekt future jest w stanie bezpiecznym zostać zmodyfikowane, może lepiej dołączyć oświadczenie wait.

Powiązane problemy