C ++ 11中的异步/期货数量

时间:2012-04-24 15:48:41

标签: c++ c++11 future

我正在尝试一个程序:

#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

对我来说,这个程序崩溃了。我怀疑,同时实际运行的期货数量有限制。如果我将迭代次数减少到几个订单,它就会起作用。

所以,有两个问题:

  1. C ++ 11中是否存在实际运行期货的限制?

  2. 为什么这段代码会崩溃?如果我在“async()”之后立即明确地执行“get()”,它必须在下一次迭代之前完成未来,这意味着一次只能运行一个未来。

  3. 更新

    我已将代码简化为:

    #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++
    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
    

    和主题:

    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。

4 个答案:

答案 0 :(得分:4)

  1. 显然存在实现限制,就像数组的大小有限一样。如果启动策略是lauch :: async并且系统无法启动新线程,则std :: async可以发出错误信息'resource_unavailable_try_again'。但是你没有收到这个错误。

  2. 程序不应该崩溃,不适合我(VS11 x64,发布版本,相同的源代码和命令行)。

    我相信即使没有.get(),程序也不会同时进行多个异步操作。将future指定给局部变量,将来每次循环迭代都会被销毁,在下一次循环迭代中启动另一个循环之前强制异步操作​​完成。

答案 1 :(得分:1)

尝试使用try-catch将代码括在main()中,并检查它是否抛出std :: exception。这可能会给出一个提示。 除此之外,VS中的C ++ 11仍然是测试版。

答案 2 :(得分:1)

  1. 不,标准没有说关于线程支持库的限制(包括线程,未来等)。

  2. 这取决于线程支持库和底层API的实现质量。如你所说f.get()等待任务编译(这种行为需要C ++标准)。当库实现可能不重用诸如底层API的线程句柄之类的资源时,可能导致系统资源不足和程序崩溃。这是一种图书馆实施的质量。

答案 3 :(得分:0)

如果您使用g ++与std = c ++ 11选项,请确保您拥有最新版本并与pthread链接。

例如,在CodingGround上,您获得的默认编译(使用“编译”按钮)是:

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

并且“what():未知错误-1”失败。但您可以手动将 -lpthread 添加到编译命令:

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

它会正常工作。