在我的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();
}
答案 0 :(得分:1)
OpenMP与其他线程机制的交互故意被排除在规范之外,因此在很大程度上取决于实现。 GNU OpenMP运行时在TLS中保存一个指向线程池的指针,并将其传播到(嵌套)团队中。通过pthread_create
(或boost::thread
或std::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的主要好处将会丢失。