Pytanie Liczba asynchronicznych / futures w C ++ 11


Próbuję programu:

#include <iostream>
#include <thread>
#include <future>

int foo() {
  return 0;
}

int main(int argc, char* argv[]) {
  for (auto i = 0L; i < 10000; ++i) {
    auto f = std::async(foo);
    f.get();
  }
  return 0;
}

Kompilator VS11 x64.

Budować:

cl /EHsc /Zi async.cpp && async

Dla mnie ten program się zawiesza. Podejrzewam, że istnieje limit liczby fizycznych kontraktów futures w tym samym czasie. Jeśli zmniejszę liczbę iteracji do kilku zamówień, to działa.

Tak więc dwa pytania:

  1. Czy istnieje limit faktycznie działających kontraktów terminowych w C ++ 11?

  2. Dlaczego ten kod w ogóle się zawiesza? Jeśli jawnie zrobię "get ()" zaraz po "async ()", to musi on ukończyć przyszłość przed kolejną iteracją, co oznacza, że ​​tylko jedna przyszłość biegnie jednocześnie.

AKTUALIZACJA

Uprościliśmy kod, aby:

#include <future>

int main(int argc, char* argv[]) {
  for (auto i = 0L; i < 1000000; ++i) {
    auto f = std::async([](){ return 0; });
    f.get();
  }
  return 0;
}

I nadal mi się to nie udaje. Nie rzuca, sprawdziłem to. Ale teraz mam widoczny ślad stosu:

async.exe!_Mtx_unlock(_Mtx_internal_imp_t * * mtx) Line 229  C++
async.exe!std::_Mtx_unlockX(_Mtx_internal_imp_t * * _Mtx) Line 84  C++
async.exe!std::_Mutex_base::unlock() Line 47  C++
async.exe!std::unique_lock<std::mutex>::~unique_lock<std::mutex>() Line 284  C++
async.exe!std::_Associated_state<int>::_Set_value(int && _Val, bool _At_thread_exit) Line 358  C++
async.exe!std::_Packaged_state<int __cdecl(void)>::_Call_immediate() Line 569  C++
async.exe!std::_Async_state<int>::`std::U_Nil::ain::ain'::`3'::<lambda_A200A86DFF9A63A1>::operator()() Line 700  C++
async.exe!??$_ApplyX@X@?$_Callable_obj@V<lambda_A200A86DFF9A63A1>@?2???$?0V?$_Bind@$0A@XV<lambda_23AC5A2FBB53FD4D>@?5?main@U_Nil@std@@U23@U23@U23@U23@U23@U23@@std@@@?$_Async_state@H@std@@QEAA@$$QEAV?$_Bind@$0A@XV<lambda_23AC5A2FBB53FD4D>@?5?main@U_Nil@std@@U23@U23@U23@U23@U23@U23@@3@@Z@$0A@@std@@QEAAXXZ() Line 420  C++
async.exe!?_Do_call@?$_Func_impl@U?$_Callable_obj@V<lambda_A200A86DFF9A63A1>@?2???$?0V?$_Bind@$0A@XV<lambda_23AC5A2FBB53FD4D>@?5?main@U_Nil@std@@U23@U23@U23@U23@U23@U23@@std@@@?$_Async_state@H@std@@QEAA@$$QEAV?$_Bind@$0A@XV<lambda_23AC5A2FBB53FD4D>@?5?main@U_Nil@std@@U23@U23@U23@U23@U23@U23@@3@@Z@$0A@@std@@V?$allocator@V?$_Func_class@XU_Nil@std@@U12@U12@U12@U12@U12@U12@@std@@@2@XU_Nil@2@U42@U42@U42@U42@U42@U42@@std@@UEAAXXZ() Line 217  C++
async.exe!std::_Func_class<void,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>::operator()() Line 486  C++
async.exe!`Concurrency::details::_MakeVoidToUnitFunc'::`3'::<lambda_25D33530A43E1C90>::operator()() Line 1056  C++
async.exe!std::_Callable_obj<`Concurrency::details::_MakeVoidToUnitFunc'::`3'::<lambda_25D33530A43E1C90>,0>::_ApplyX<Concurrency::details::_Unit_type>() Line 420  C++
async.exe!std::_Func_impl<std::_Callable_obj<`Concurrency::details::_MakeVoidToUnitFunc'::`3'::<lambda_25D33530A43E1C90>,0>,std::allocator<std::_Func_class<Concurrency::details::_Unit_type,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil> >,Concurrency::details::_Unit_type,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>::_Do_call() Line 217  C++
async.exe!std::_Func_class<Concurrency::details::_Unit_type,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>::operator()() Line 486  C++
async.exe!`Concurrency::details::_Task_impl<Concurrency::details::_Unit_type>::_ScheduleTask'::`3'::<lambda_7D9BCD859405C05B>::operator()() Line 325  C++
async.exe!Concurrency::details::_PPLTaskHandle<`Concurrency::details::_Task_impl<Concurrency::details::_Unit_type>::_ScheduleTask'::`3'::<lambda_7D9BCD859405C05B> >::operator()() Line 72  C++
async.exe!Concurrency::details::_UnrealizedChore::_InvokeBridge<Concurrency::details::_PPLTaskHandle<`Concurrency::details::_Task_impl<Concurrency::details::_Unit_type>::_ScheduleTask'::`3'::<lambda_7D9BCD859405C05B> > >(Concurrency::details::_PPLTaskHandle<`Concurrency::details::_Task_impl<Concurrency::details::_Unit_type>::_ScheduleTask'::`3'::<lambda_7D9BCD859405C05B> > * _PChore) Line 4190  C++
async.exe!Concurrency::details::_UnrealizedChore::_UnstructuredChoreWrapper(Concurrency::details::_UnrealizedChore * pChore) Line 275  C++
async.exe!Concurrency::details::_PPLTaskChore::_DeletingChoreWrapper(Concurrency::details::_UnrealizedChore * pChore) Line 78  C++
async.exe!Concurrency::details::InternalContextBase::ExecuteChoreInline(Concurrency::details::WorkItem * pWork) Line 1600  C++
async.exe!Concurrency::details::InternalContextBase::Dispatch(Concurrency::DispatchState * pDispatchState) Line 1704  C++
async.exe!Concurrency::details::FreeThreadProxy::Dispatch() Line 191  C++
async.exe!Concurrency::details::ThreadProxy::ThreadProxyMain(void * lpParameter) Line 173  C++
kernel32.dll!0000000076df652d()  Unknown
ntdll.dll!0000000076f2c521()  Unknown

i wątki:

Unflagged       1864    0   Worker Thread   ntdll.dll thread    ntdll.dll!0000000076f518ca  Normal
Unflagged       10964   0   Main Thread Main Thread async.exe!do_signal Normal
Unflagged       7436    0   Worker Thread   ntdll.dll thread    ntdll.dll!0000000076f52c1a  Normal
Unflagged       10232   0   Worker Thread   async.exe!Concurrency::details::ThreadProxy::ThreadProxyMain    async.exe!Concurrency::details::ThreadProxy::SuspendExecution   Normal
Unflagged   >   10624   0   Worker Thread   async.exe!Concurrency::details::ThreadProxy::ThreadProxyMain    async.exe!_Mtx_unlock   Normal
Unflagged       4756    0   Worker Thread   async.exe!Concurrency::details::ThreadProxy::ThreadProxyMain    async.exe!Concurrency::details::ThreadProxy::SuspendExecution   Normal
Unflagged       11100   0   Worker Thread   async.exe!Concurrency::details::ThreadProxy::ThreadProxyMain    async.exe!Concurrency::details::InternalContextBase::WaitForWork    Normal
Unflagged       6440    0   Worker Thread   async.exe!Concurrency::details::ThreadProxy::ThreadProxyMain    async.exe!std::vector<std::pair<void (__cdecl*)(void * __ptr64),void * __ptr64>,std::allocator<std::pair<void (__cdecl*)(void * __ptr64),void * __ptr64> > >::_Tidy Normal

Używam VS 11.0.40825.2 PREREL.


12
2018-04-24 15:48


pochodzenie


Brzmi jak błąd kompilatora. - R. Martinho Fernandes
Debugger powinien pomóc ci zrozumieć, dlaczego kod ulega awarii. Spróbuję tego, zanim założę, że kompilator jest zepsuty. - Steve Townsend
@SteveTownsend: Cóż, kod wydaje się dość prosty i zgodny z C ++ 11. Jeśli się zawiesza (podpisz niezdefiniowane zachowanie) i kod jest prawidłowy, to istnieje jest problem z implementacją (kompilator + środowisko wykonawcze). Oznacza to, że chyba nie udało mi się zobaczyć, że kod jest niepoprawny. Zgadzam się, że w zrozumieniu jest wartość czemu to jest złamane. - David Rodríguez - dribeas
@Alexander - czy to z debugowaniem czy wydaniem? Wypróbuj Debugowanie, jeśli nie zostało to już zrobione. Czy możesz dodać dane wyjściowe, aby policzyć liczbę iteracji przed awarią? Czy dodanie tutaj obsługi wyjątków robi jakąkolwiek różnicę? - Steve Townsend
@Alexander: Brzmi jak wyścig w ConcRT. ID zgłoś zgłoszenie błędu... - ildjarn


Odpowiedzi:


  1. Oczywiście są limity implementacji, tak jak istnieje limit wielkości tablicy. std :: async może zasygnalizować błąd "resource_unavailable_try_again", jeśli zasadą uruchamiania jest Lauch :: Async i system nie może uruchomić nowego wątku. Ale nie otrzymujesz tego błędu.

  2. Program nie powinien się zawieszać i nie działa dla mnie (VS11 x64, wersja wydania, to samo źródło i linia poleceń).

    Wierzę, że nawet bez .get() program nie będzie miał więcej niż jedną asynchroniczną operację naraz. Przypisujesz przyszłość do zmiennej lokalnej, a przyszłość jest niszczona w każdej iteracji pętli, zmuszając operację asynchroniczną do ukończenia przed uruchomieniem kolejnej w kolejnej iteracji pętli.


4
2018-04-24 18:16





Spróbuj zamknąć kod w main () przy pomocy catch-u i sprawdź, czy generuje wyjątek std ::. To może dać wskazówkę. Poza tym C ++ 11 w VS nadal jest w wersji beta.


1
2018-04-29 15:28



A beta jest wtedy, gdy raporty o błędach są najcenniejsze. - Ben Voigt


  1. Nie, normy nie określają ograniczeń dotyczących biblioteki obsługi wątków (obejmują wątek, przyszłość itp.).

  2. Zależy to od jakości implementacji biblioteki obsługi wątków i bazowego API. Tak jak mówisz f.get() czeka na komplację zadań (to zachowanie wymagało standardu C ++). Gdy implementacja biblioteki NIE może ponownie użyć zasobów, takich jak uchwyt wątku bazowego API, MOŻE spowodować brak systemu resouce i awarię programu. Jest to jakość implementacji biblioteki.


1
2018-05-02 07:38





Jeśli używasz g ++ z opcją std = c ++ 11, upewnij się, że masz najnowszą wersję i link do pthread.

Na przykład w CodingGround domyślną kompilacją, którą otrzymujesz (przyciskiem Compile) jest:

g++ -std=c++11 -o main *.cpp 

i zawodzi "what (): Unknown error -1". Ale możesz ręcznie dodać -lpthread do komendy kompilacji:

g++ -std=c++11 -o main -lpthread *.cpp

i będzie działać dobrze.


0
2018-03-17 06:43