简体   繁体   English

如何找出openMP并行区域内?

[英]How to find out if inside an openMP parallel region?

In my code, I want to avoid throwing exceptions from inside any openMP parallel region (because this results in an unhandled exception if not caught within the same region). 在我的代码中,我想避免在任何openMP并行区域内抛出异常(因为如果未在同一区域内捕获,则会导致未处理的异常)。 To this end, I tried to use the openmp run-time library function 为此,我尝试使用openmp运行时库函数

omp_in_parallel();

to decide whether to throw an exception or write out an error message and terminate. 决定是抛出异常还是写出错误消息并终止。 However, under gcc 4.7.0 this will not work if there is only one thread to a parallel region: 但是,在gcc 4.7.0下,如果只有一个并行区域的线程,这将不起作用:

#include <iostream>
#include <omp.h>

void do_something()
{
  if(!omp_in_parallel())           // omp_in_parallel() returns false!
    throw 3;                       // so should be able to safely throw
}

int main()
{
  omp_set_num_threads(1);
  try {
#   pragma omp parallel
    do_something();
  } catch(int e) {
    std::cerr<<"error: '"<<e<<"'\n";  // never gets here
  }
}

does not result in error: '3' but in terminate called after throwing an instance of 'int' Abort . 不会导致错误:'3'但是在抛出'int'Abort实例后调用终止

Is this the correct behaviour (of omp_in_parallel() )? 这是正确的行为( omp_in_parallel() )吗? (the openMP standard appears sufficiently vague) or a bug in gcc? (openMP标准显得足够模糊)或gcc中的错误? How can I fix the above code for do_something() so that it throws only when not in a parallel region? 如何修复do_something()的上述代码,以便仅在不在并行区域时抛出?

The OpenMP standard states that omp_in_parallel() returns true if and only if the enclosing parallel region is active. OpenMP标准规定,当且仅当封闭的parallel区域处于活动状态时, omp_in_parallel()返回true An active parallel region is defined to be one that is executed by a team consisting of more than one thread . 活动parallel区域被定义为由包含多个线程的团队执行的区域。 In your case you have an inactive parallel region since there is one thread only. 在您的情况下,您有一个非活动的并行区域,因为只有一个线程。 Thus omp_in_parallel() returns false and the throw is executed. 因此, omp_in_parallel()返回false并执行throw It errs because the OpenMP standard restricts exceptions to the same parallel region and thread: 它错误,因为OpenMP标准限制同一并行区域和线程的异常:

A throw executed inside a parallel region must cause execution to resume within the same parallel region, and the same thread that threw the exception must catch it. parallel区域内执行的throw必须导致执行在同一parallel区域内恢复,并且抛出异常的同一线程必须捕获它。

This makes your code non-conformant since you let an exception pass unhandled through the parallel region. 这使得您的代码不符合要求,因为您通过并行区域处理未处理的异常。 The same error is emitted by the Intel OpenMP run-time so it is not a GCC-specific behaviour. 英特尔OpenMP运行时发出相同的错误,因此它不是特定于GCC的行为。

What happens actually is that GCC transforms the OpenMP region by wrapping your code in a try/catch block with a catch-all exception filter: 实际上会发生的事情是GCC通过将代码包装在带有catch-all异常过滤器的try/catch块中来转换OpenMP区域:

#pragma omp parallel [child fn: main.omp_fn.0 (???)]
  {
    try
      {
        do_something ();
      }
    catch
      {
        <<<eh_filter (NULL)>>>
          {
            terminate ();
          }
      }
    #pragma omp return
  }

It is this catch-all exception filter that is responsibe for the termination message. 正是这个全部捕获的异常过滤器负责终止消息。

To resolve this the entire try/catch block should be inside the parallel region and not vice versa: 要解决这个问题,整个try/catch块应该并行区域 ,而不是相反:

# pragma omp parallel
{
   try {
      do_something();
   } catch(int e) {
      std::cerr<<"error: '"<<e<<"'\n";  // never gets here
   }
}

(the additional block was added to make Intel C++ Compiler happy; it is not strictly necessary for GCC) (添加了附加块以使英特尔C ++编译器满意;对于GCC来说并不是绝对必要的)

This outputs error: '3' as expected. 这输出error: '3'如预期的那样。

Edit: The funny thing is that your exception handler doesn't even make it into the final binary. 编辑:有趣的是,你的异常处理程序甚至没有进入最终的二进制文件。 Even given the default optimisation level of GCC (ie compiling with g++ -fopenmp -o prog prog.cc ), the redundancy eliminator is able to detect that your exception handler would never be reached because of the implicit inner exception handler and thus your handler is removed. 即使给定GCC的默认优化级别(即使用g++ -fopenmp -o prog prog.cc ),冗余消除器也能够检测到由于隐式内部异常处理程序而永远不会到达您的异常处理程序,因此您的处理程序是除去。 Then the compiler finds out that the implicit termination handler is also redundant, since there is already a top-level exception handler for the whole process that does the same (calls terminate() ) and thus removes even the implicit one. 然后编译器发现隐式终止处理程序也是冗余的,因为已经有一个顶级异常处理程序用于执行相同的整个进程(调用terminate() ),因此甚至删除了隐式终止处理程序。 The final code is so lean and mean - no exception handlers at all: 最终的代码是如此精简和卑鄙 - 根本没有异常处理程序:

;; Function int main() (main, funcdef_no=970, decl_uid=20816, cgraph_uid=212)

int main() ()
{
  int e;
  int D.20855;
  struct basic_ostream & D.20854;
  struct basic_ostream & D.20853;
  void * D.20852;
  register int * D.20819;

<bb 2>:
  omp_set_num_threads (1);
  __builtin_GOMP_parallel_start (main._omp_fn.0, 0B, 0);
  main._omp_fn.0 (0B);
  __builtin_GOMP_parallel_end ();
  D.20855_1 = 0;
  // <------ See, ma', no exception handling at all :)

<L0>:
  return D.20855_1;

}

;; Function <built-in> (main._omp_fn.0, funcdef_no=976, decl_uid=20857, cgraph_uid=222)

<built-in> (void * .omp_data_i)
{
<bb 2>:
  do_something ();
  return;
  // <------ See, ma', they've nuked the implicit termination handler

}

One gets to love the -fdump-tree-all GCC option. 人们喜欢-fdump-tree-all GCC选项。

Edit: As to the question on how to fix do_something() - use omp_get_level() instead of omp_in_parallel() : 编辑:关于如何修复do_something() - 使用omp_get_level()而不是omp_in_parallel()

void do_something()
{
   if(omp_get_level() == 0)
     throw 3;
}

omp_get_level() returns the level of nesting of the parallel regions that enclose the call, no matter if they are active or not. omp_get_level()返回包含调用的parallel区域的嵌套级别,无论它们是否处于活动状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM