从代码中覆盖 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 - 真的的主要内容,如果未能解决你的问题,请参考以下文章

python OMP_NUM_THREADS.py

如何修复 OpenMP 程序的 gdb 运行中的线程数

从代码覆盖中排除生成的源而不影响整体代码覆盖

使用 Cobertura 从代码覆盖中排除方法

如何从业力代码覆盖率报告中排除文件?

从 .net 6 的代码覆盖范围中排除 Program.cs [重复]