如何在工作线程中重用由主线程创建的OMP线程池?

时间:2016-07-07 20:39:34

标签: c++ multithreading boost openmp

在我的c ++应用程序的开头附近,我的主线程使用OMP来并行化几个for循环。在第一个并行化的for循环之后,我看到所使用的线程在应用程序的持续时间内仍然存在,并且使用该命令(在CentOS 7中工作)重用于从主线程执行的循环的后续OMP:

for i in $(pgrep myApplication); do ps -mo pid,tid,fname,user,psr -p $i;done

稍后在我的程序中,我从主线程启动一个boost线程,我在其中使用OMP并行化for循环。此时,我看到创建了一组全新的线程,这些线程具有相当大的开销。

是否有可能在boost线程中使OMP并行for循环重用主线程创建的原始OMP线程池?

编辑:一些伪代码:

myFun(data)
{

    // Want to reuse OMP thread pool from main here.
    omp parallel for
    for(int i = 0; i < N; ++i)
    {
       // Work on data
    }

}


main
{

    // Thread pool created here.
    omp parallel for
    for(int i = 0; i < N; ++i)
    {
        // do stuff
    }


    boost::thread myThread(myFun) // Constructor starts thread.

    // Do some serial stuff, no OMP.

    myThread.join();


}

1 个答案:

答案 0 :(得分:1)

OpenMP与其他线程机制的交互故意被排除在规范之外,因此在很大程度上取决于实现。 GNU OpenMP运行时在TLS中保存一个指向线程池的指针,并将其传播到(嵌套)团队中。通过pthread_create(或boost::threadstd::thread)启动的线程不会继承指针,因此会生成一个新池。其他OpenMP运行时也可能就是这种情况。

标准中要求在大多数实现中基本上强制这种行为。它是关于 threadprivate 变量的语义,以及它们如何在从同一个线程分叉的不同并行区域中保留它们的值(OpenMP标准,2.15.2 threadprivate Directive):

  

只有满足以下所有条件时,才能保证非初始线程的threadprivate变量中的数据值在两个连续的活动parallel区域之间保持不变:

     
      
  • parallel区域都没有嵌套在另一个显式并行区域内。
  •   
  • 用于执行两个parallel区域的线程数相同。
  •   
  • 用于执行两个parallel区域的线程相关性策略是相同的。
  •   
  • 在两个parallel区域的入口处,封闭任务区域中 dyn-var 内部控制变量的值为 false
  •   
     

如果这些条件都成立,并且两个区域中都引用了threadprivate变量,则各自区域中具有相同线程编号的线程将引用该变量的相同副本。

除了性能之外,这可能是在OpenMP运行时中使用线程池的主要原因。

现在,假设由两个独立线程分叉的两个并行区域共享同一个工作线程池。并行区域由第一个线程分叉,并设置了一些threadprivate变量。稍后,第二个并行区域由同一个线程分叉,其中使用了这些threadprivate变量。但是在两个并行区域之间的某处,并行区域由第二线程分叉,并且使用来自同一池的工作线程。由于大多数实现都在TLS中保留了threadprivate变量,因此无法再断言上述语义。一种可能的解决方案是为每个单独的线程向池中添加新的工作线程,这与创建新线程池没有太大区别。

我不知道有任何变通方法可以共享工作线程池。如果可能的话,它将无法移植,因此OpenMP的主要好处将会丢失。