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

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();


}

最佳答案

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

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



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

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

我不知道任何使工作线程池共享的解决方法。如果可能的话,它不会是可移植的,因此将失去 OpenMP 的主要优势。

关于c++ - 如何在工作线程中重用由主线程创建的 OMP 线程池?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38254882/

10-11 17:59