Concurrency :: parallel_for(PPL)创建了太多线程

时间:2014-09-30 14:57:43

标签: c++ multithreading concurrency ppl

我使用Concurrency::parallel_for()的Visual Studio 2010并行模式库(PPL)来处理索引的一组任务(通常,索引集远远大于线程的数量)可以同时运行)。在进行冗长的计算之前,每个任务都从共享资源管理器请求私有工作存储资源开始(以防:在任务特定的内存映射文件上查看,但我认为如果每个任务的故事情节都相同请求从共享堆中分配私有内存。)

共享资源管理器的使用与Concurrency::critical_section同步,此处问题开始:如果第一个线程/任务在关键部分,第二个任务发出请求,则必须等到处理第一个任务的请求。然后PPL显然认为:嘿这个线程正在等待并且还有更多的任务要做,因此创建了另一个线程,导致多达870个线程主要在同一个资源管理器上等待。

现在因为处理资源请求只是整个任务的一小部分,我想告诉那个部分的PPL保持其匹配,没有等待或合作块应该导致新线程从指示开始工作线程的一部分和我的问题是:是否以及如何阻止特定线程部分创建新线程,即使它合作阻止。我不会介意在线程的处理路径下面的其他块中创建新线程,但不超过2 *(超级)内核的数量。

到目前为止我考虑过的替代方案:

  1. 排队任务并从有限数量的线程处理队列。问题:我希望,PPL的parallel_for会自行完成。

  2. 定义Concurrency::combinable<Resource> resourceSet;在Concurrency::parallel_for之外并初始化resourceSet.local()一次,以减少资源请求的数量(通过重用资源)到线程数(应该小于任务数)。问题:此优化不会阻止多余的线程创建。

  3. 预先为parallel_for循环之外的每个任务分配所需资源。问题:这会请求太多系统资源,而将资源数量限制为线程/核心数量则可以(如果没有爆炸)。

  4. 我读了http://msdn.microsoft.com/en-us/library/ff601930.aspx,&#34;不要在并行循环中反复阻塞&#34;,但遵循这里的建议将导致根本没有并行线程。

2 个答案:

答案 0 :(得分:4)

我不知道是否可以将PPL / ConcRT配置为不使用协作同步或至少限制它创建的线程数。我认为它可以通过scheduler policies进行控制,但似乎没有一个政策参数适用于此目的。

但是,即使不是以理想的方式,我也会提供一些有助于缓解问题的建议:

  • 使用非协作同步原语代替critical_section来保护资源管理器。我认为(虽然没有检查)古典WinAPI CRITICAL_SECTION应该成功。作为这方面的一个根本步骤,您可以考虑使用其他并行库来代码;例如Intel's TBB provides most of PPL API and has more(免责声明:我与之有联系)。

  • 在并行循环之外预分配许多资源。每个任务一个资源不是必需的;每个线程一个就足够了。将这些资源放入concurrent_queue,并在任务内部从队列中弹出资源,使用,然后将其推回。此外,线程可能会将其保留在combinable对象中,以便在其他任务中重用,而不是将资源返回到队列。如果队列恰好是空的(例如,如果PPL超额订阅机器),则可能存在不同的方法,例如,循环旋转,直到某个其他线程返回资源,或从管理器请求另一个资源。此外,您可以选择预先分配比线程数更多的资源,以最大限度地减少资源耗尽的可能性。

答案 1 :(得分:1)

我的答案不是&#34;&#34;使用PPL的解决方案,但我认为您可以使用taskqueue这样的线程池轻松完成,您应该看看this answer

所以你用你的作品填满队列,它确保不会超过&#39; x&#39;并行工作的任务,其中x为boost::thread::hardware_concurrency()(是再次提升......)