C ++线程未加入“没有活动异常的终止调用”
Posted
技术标签:
【中文标题】C ++线程未加入“没有活动异常的终止调用”【英文标题】:C++ thread not joining "Termination called without active exception" 【发布时间】:2017-02-09 01:26:04 【问题描述】:我正在尝试通过使用 std::thread
来加速 for 循环。该循环遍历由数百万个项目组成的列表。我将每次迭代都分配给不同的线程。
4047 次迭代后,它停止运行并抛出 terminate called without an active exception Aborted (core dumped)
我相信这个错误通常是由于线程没有正确连接引起的(如本网站其他问题所述)。但是,我确实有一个函数可以在我的 for 循环结束时加入所有线程。因为没有达到连接功能,我怀疑真正的问题是创建了太多线程。这是我第一次涉足 lambdas 和多线程,我不确定如何限制 for 循环内一次创建的线程数。
我的代码如下:
std::mutex m;
std::vector<std::thread> workers;
for ( ot.GoToBegin(), !ot.IsAtEnd(); ++ot ) // ot is the iterator
workers.push_back(std::thread([test1, test2, ot, &points, &m, this]()
// conditions depending on the current ot are checked
if ( test1 == true ) return 0; // exit function
if ( test2 == true ) return 0;
// ...etc, lots of different checks are performed..
// if conditions are passed save the current ot
m.lock();
points.push_back( ot.GetIndex() );
m.unlock();
));
// end of iteration
std::for_each(workers.begin(), workers.end(), [](std::thread &t)
t.join(); // join all threads
);
任何帮助将不胜感激
【问题讨论】:
C++ terminate called without an active exception的可能重复 创建数百万个线程不会很漂亮 - 我建议查看线程池。 该问题的解决方案是拥有一个连接所有线程的函数。如上所述,我已经包含了一个连接函数,用于在 for 循环完成时连接所有线程 【参考方案1】:由于您每次都在同一迭代中遇到错误,因此原因不在于“加入”本身。很可能,系统上每个进程的线程数受限于 4096 或类似数量,请参阅Maximum number of threads per process in Linux?
当您创建线程号 4047 左右时,std::thread 的构造函数会抛出异常,并且您永远不会进入“join”语句。
我建议你保留一个不是 std::tread(s) 而是 std::future(s) 的向量。代码大致如下所示:
typedef std::future<int> Future;
std::vector<Future> results;
for (...)
results.emplace_back( std::async(std::launch::async,
[...]() /* roughly same code as in your thread function */ ) );
for ( Future& result : results)
auto value = result.get(); //waits for the task to finish
// process your values ...
未来依赖于内部线程池,因此您不会用完线程。这些期货将在线程可用时异步执行。
【讨论】:
感谢您的建议。听起来确实受到系统的限制。我像你说的那样实现了一个期货向量,但是在抛出系统错误Resource temporarily unavailable
之前它也运行了4047次迭代。我设置了一个计数器,一次分配 4000 个期货块,等到它们完成,清除向量并分配另一个 4000 个期货块。这行得通,但开销是巨大的 - 比不并行时慢 50 倍以上。回到绘图板,我猜。
干得好!很可能您需要一个带有“线程池”的真实库,例如英特尔待定。或者,您可以搜索并使用一些临时线程池模块。当然,这需要重新设计一些数据结构。例如,应该去全局互斥锁。相反,每个线程都应该携带其本地点向量,直到它准备好合并它们,就像在 TBB 模板“parallel_reduce”中一样。以上是关于C ++线程未加入“没有活动异常的终止调用”的主要内容,如果未能解决你的问题,请参考以下文章