从代码中覆盖 OMP_NUM_THREADS - 真的
Posted
技术标签:
【中文标题】从代码中覆盖 OMP_NUM_THREADS - 真的【英文标题】:Overriding OMP_NUM_THREADS from code - for real 【发布时间】:2019-05-29 13:00:13 【问题描述】:到目前为止我能找到的所有答案都建议致电omp_set_num_threads
。虽然对于大多数情况来说这是一个正确的答案,但它对我不起作用。在内部,调用omp_set_num_threads
会导致创建每线程ICV(或修改,如果当前线程已经有一个),并且线程数存储在那里。这意味着如果有一个不同的线程启动一个并行区域,它将看不到我们的新值。所以调用 omp_set_num_threads != 设置 OMP_NUM_THREADS 环境变量。
有没有办法改变全局 ICV?
旁注 - 我为什么要这样做:我正在使用一个库为我生成一个工作线程,所以我并不能真正控制它的生命周期。
最简单的重现示例:
export OMP_NUM_THREADS=3
#include <omp.h>
#include <iostream>
#include <thread>
void job()
#pragma omp parallel
if (omp_get_thread_num() == 0)
std::cout << "Num threads:" << omp_get_num_threads() << std::endl;
;
int main ()
omp_set_num_threads(2);
#pragma omp parallel
if (omp_get_thread_num() == 0)
std::cout << "Num threads:" << omp_get_num_threads() << std::endl;
;
std::thread t(job);
t.join();
这会产生
Num threads:2
Num threads:3
【问题讨论】:
【参考方案1】:您尝试实现的问题超出了 OpenMP 的规范。 OpenMP 假定它是应用程序进程中唯一的编程模型,因此它确实知道当您创建一个也执行 OpenMP 代码的新线程时会发生什么。
具体来说,对于您的问题:ICV num-threads
是线程私有 ICV,这意味着对 omp_set_num_threads()
的调用仅影响存储在调用 omp_set_num_threads()
的线程中的 ICV。
因此,新的std::thread
将收到一个从环境变量初始化的新副本。您将无法从产生新线程的主线程更改它。
【讨论】:
【参考方案2】:从代码中覆盖 OMP_NUM_THREADS...
改变这个:
int main ()
omp_set_num_threads(2);
#pragma omp parallel
if (omp_get_thread_num() == 0)
std::cout << "Num threads:" << omp_get_num_threads() << std::endl;
;
std::thread t(job);
t.join();
到这里:
int main ()
#pragma omp parallel num_threads(2)
if (omp_get_thread_num() == 0)
std::cout << "Num threads:" << omp_get_num_threads() << std::endl;
;
std::thread t(job);
t.join();
我相信这适用于 Microsoft 编译器,这些编译器在 2003 年左右被困在 OpenMP 的某个地方。如果我没记错的话,2003 年发布的 OpenMP 大概是 2.0 或 2.1 版。
另见Difference between num_threads vs. omp_set_num_threads vs OMP_NUM_THREADS。
【讨论】:
以上是关于从代码中覆盖 OMP_NUM_THREADS - 真的的主要内容,如果未能解决你的问题,请参考以下文章