在我的 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::thread
或 std::thread
)启动的线程不会继承该指针,因此会生成一个新池。其他 OpenMP 运行时可能也是这种情况。
标准中有一项要求基本上在大多数实现中强制执行此类行为。它是关于 threadprivate 变量的语义以及它们的值如何在从同一线程派生的不同并行区域中保留(OpenMP 标准,2.15.2 threadprivate
Directive):
The values of data in the threadprivate variables of non-initial threads are guaranteed to persist between two consecutive active
parallel
regions only if all of the following conditions hold:
- Neither
parallel
region is nested inside another explicit parallel region.- The number of threads used to execute both
parallel
regions is the same.- The thread affinity policies used to execute both
parallel
regions are the same.- The value of the dyn-var internal control variable in the enclosing task region is false at entry to both
parallel
regions.If these conditions all hold, and if a threadprivate variable is referenced in both regions, then threads with the same thread number in their respective regions will reference the same copy of that variable.
除了性能之外,这可能是在 OpenMP 运行时中使用线程池的主要原因。
现在,想象一下由两个独立线程 fork 的两个并行区域共享同一个工作线程池。第一个线程 fork 了一个并行区域,并设置了一些线程私有(private)变量。后来,同一个线程 fork 出第二个并行区域,其中使用了那些线程私有(private)变量。但是在两个并行区域之间的某处,一个并行区域由第二个线程 fork ,并且使用来自同一池的工作线程。由于大多数实现在 TLS 中保留 threadprivate 变量,因此不再断言上述语义。一种可能的解决方案是为每个单独的线程向池中添加新的工作线程,这与创建新的线程池没有太大区别。
我不知道有任何解决方法可以共享工作线程池。如果可能的话,它也不是可移植的,因此将失去 OpenMP 的主要优势。
关于c++ - 如何在工作线程中重用主线程创建的 OMP 线程池?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38254882/