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 ++线程未加入“没有活动异常的终止调用”的主要内容,如果未能解决你的问题,请参考以下文章

python 通过paramiko模块批量执行ssh命令

在C ++中,是否有任何理由产生并立即加入一个线程,而不是直接调用该函数?

在破坏调用期间从另一个线程未定义的行为调用对象上的方法?

C ++回调计时器实现

C ++中的条件变量问题

c ++ OpenMP关键:“单向”锁定?