【问题标题】:avoid nested parallel region避免嵌套并行区域
【发布时间】:2011-12-22 22:37:17
【问题描述】:

我想编写一个采用 openMP 并行性的函数,但无论是否从并行区域内调用都应该可以工作。所以我使用了if 子句来抑制并行性,但这并不像我想的那样工作:

#include <omp.h>
#include <stdio.h>

int m=0,s=0;

void func()
{
  bool p = omp_in_parallel();
  // if clause to suppress nested parallelism
#pragma omp parallel if(!p)
  {
    /* do some massive work in parallel */
#pragma omp master
    ++m;
#pragma omp single
    ++s;
  }
}

int main()
{
  fprintf(stderr,"running func() serial:\n");
  m=s=0;
  func();
  fprintf(stderr," m=%d s=%d\n",m,s);

  fprintf(stderr,"running func() parallel:\n");
  m=s=0;
#pragma omp parallel
  func();
  fprintf(stderr," m=%d s=%d\n",m,s);
}

创建输出

running func() serial:
 m=1 s=1
running func() parallel:
 m=16 s=16

因此对func() 的第一次调用运行良好:ms 获得了应有的值 1,但从并行区域内对func() 的第二次调用确实创建了嵌套并行(16 个团队每个线程 1 个),即使这被抑制了。那就是 omp masteromp single 指令绑定到前面的 omp parallel if(!p) 指令而不是外部并行区域。

当然可以通过下面的代码解决这个问题

void work()
{
  /* do some massive work in parallel */
#pragma omp master
  ++m;
#pragma omp single
  ++s;
}

void func()
{
  if(omp_in_parallel())
    work();
  else
#pragma omp parallel
    work();
}

但这需要定义一个额外的函数等。是否可以在单个函数中执行此操作(并且无需重复代码)?

【问题讨论】:

    标签: openmp


    【解决方案1】:

    OpenMP 构造将始终绑定到最里面的包含构造,即使它未处于活动状态。因此,我认为在为两个代码路径保留#pragma omp parallel 时是不可能的(至少在提供有关问题的信息的情况下)。

    请注意,最好认为它的行为是这样的,因为否则使用条件很容易导致非常有问题(阅读错误)的代码。看下面的例子:

    void func(void* data, int size)
    {
       #pragma omp parallel if(size > 1024)
       {
           //do some work
           #pragma omp barrier
           //do some more work
       }
    }
    
    ...
    #pragma omp parallel
    {
       //create foo, bar, bar varies massively between different threads (so sometimes bigger, sometimes smaller then 1024
       func(foo, bar);
       //do more work
    }
    

    一般来说,程序员不需要知道被调用函数的实现细节,只需要知道它们的行为。所以我真的不必关心func 是否创建了一个嵌套的parallel 部分,以及它在什么条件下创建了一个嵌套部分。但是,如果barrier 将绑定到外部parallel,如果内部不活动,则此代码将是错误的,因为外部parallel 部分的一些线程遇到barrier 而有些则没有。因此这些细节隐藏在包含parallel 的最里面,即使它不活动。

    就我个人而言,我从未遇到过我希望它表现不同的情况(这会违反信息隐藏等),所以也许你应该告诉我们更多关于你正在努力完成什么以获得更好的答案。

    【讨论】:

      【解决方案2】:

      我查看了 openMP 标准。 if 子句实际上有些误导,因为 #pragma omp parallel 指令不是有条件的(正如我最初认为的那样)。相反,if 子句可能会将线程数限制为 1,从而抑制并行化。

      但是,这意味着 omp singleomp master 不能用于线程安全的每进程一次的全局共享变量写入。

      【讨论】:

      • 是的,它确实暗示了这一点,而且它确实不应该用于那个,因为你通常不能保证(信息隐藏和所有)在外部级别上没有嵌套的并行性。对共享变量进行线程安全的访问更多是互斥锁(omp 中的锁)的用例。你的描述你希望它如何工作听起来并不那么有用(如果有多个线程调用do_func,你只希望其中一个线程(因此调用)写入全局变量?我不知道你的具体情况,但这听起来不是很有用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-16
      • 2016-11-19
      • 2014-08-23
      • 2018-10-07
      • 2023-01-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多