Подтвердить что ты не робот

Количество асинхронных/фьючерсов в С++ 11

Я пробую программу:

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

Компилятор VS11 x64.

Сложение:

cl /EHsc /Zi async.cpp && async

Для меня эта программа выйдет из строя. Я подозреваю, что число фьючерсов, физически работающих одновременно, ограничено. Если я уменьшу количество итераций до нескольких порядков, он будет работать.

Итак, два вопроса:

  • Есть ли предел фактических запусков фьючерсов в С++ 11?

  • Почему этот код вообще не работает? Если я явно делаю "get()" сразу после "async()", он должен завершить будущее до следующей итерации, что означает, что за один раз запускается только одно будущее.

UPDATE

Я упростил код:

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

И он все еще падает для меня. Он не бросает, я проверил это. Но теперь у меня есть видимая трассировка стека:

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++
[email protected]@[email protected]<lambda_A200A86DFF9A63A1>@[email protected][email protected]<lambda_23AC5A2FBB53FD4D>@[email protected][email protected]@@[email protected]@[email protected]@[email protected]@@[email protected]@@[email protected]@[email protected]@[email protected][email protected][email protected]<lambda_23AC5A2FBB53FD4D>@[email protected][email protected]@@[email protected]@[email protected]@[email protected]@@[email protected]@[email protected][email protected]@[email protected]@QEAAXXZ() Line 420  C++
[email protected][email protected][email protected]<lambda_A200A86DFF9A63A1>@[email protected][email protected]<lambda_23AC5A2FBB53FD4D>@[email protected][email protected]@@[email protected]@[email protected]@[email protected]@@[email protected]@@[email protected]@[email protected]@[email protected][email protected][email protected]<lambda_23AC5A2FBB53FD4D>@[email protected][email protected]@@[email protected]@[email protected]@[email protected]@@[email protected]@[email protected][email protected]@[email protected]@[email protected][email protected][email protected]@@[email protected]@[email protected]@[email protected]@@[email protected]@@[email protected][email protected]@[email protected]@[email protected]@[email protected]@@[email protected]@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

и потоки:

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

Я использую VS 11.0.40825.2 PREREL.

4b9b3361

Ответ 1

  • Очевидно, что существуют пределы реализации, точно так же, как есть ограничение на то, насколько большой массив может быть. std:: async может сигнализировать об ошибке "resource_unavailable_try_again", если политика запуска lauch:: async и система не может запустить новый поток. Но вы не получаете эту ошибку.

  • Программа не должна аварийно завершаться и не для меня (VS11 x64, релиз сборки, тот же источник и командная строка).

    Я считаю, что даже без .get() у программы не было бы одновременно более одной асинхронной операции. Вы назначаете будущее локальной переменной, будущее уничтожает каждую итерацию цикла, заставляя асинхронную операцию завершить, прежде чем запускать другую в следующей итерации цикла.

Ответ 2

Попробуйте вставить свой код в main() с помощью try-catch и проверить, выбрасывает ли он std:: exception. Это может дать намек. Кроме того, С++ 11 в VS все еще является бета-версией.

Ответ 3

  • Нет, стандарты не говорят об ограничении библиотеки поддержки потоков (включая поток, будущее и т.д.).

  • Это зависит от качества реализации библиотеки поддержки потоков и базового API. Как вы говорите, f.get() ждет компиляции задачи (для этого требуется С++ Standard). Когда реализация библиотеки НЕ может повторно использовать ресурсы, такие как основной дескриптор потока API, это может привести к сбою системы и сбою программы. Это качество реализации библиотеки.

Ответ 4

Если вы используете g++ с опцией std = С++ 11, убедитесь, что у вас есть последняя версия и ссылка на pthread.

Например, на CodingGround компиляция по умолчанию, которую вы получаете (с помощью кнопки компиляции), составляет:

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

и он не работает с "what(): Неизвестная ошибка -1" . Но вы можете вручную добавить команду -lpthread в команду компиляции:

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

и все будет хорошо.