19

我想知道在 OMP 关键部分中抛出 C++ 异常是否安全。

#pragma omp critical (my_critical_section)
{
    ...
    throw my_exception("failed")
    ...       
}

g++ 没有抱怨。我很困惑,因为它抱怨return关键部分内的语句。它返回错误:invalid exit from OpenMP structured block当我写

#pragma omp critical (my_critical_section)
{
    ...
    return;
    ...       
}

那么,为什么给临界区一个异常就可以了,但是用一个return语句就不行了呢

4

1 回答 1

20

不,不允许有例外的关键部分。g++在这种情况下不会抱怨,但它try/catch会在关键部分的块周围默默地插入一个隐式。例如下面的代码:

#pragma omp critical (my_crit)
{
   throw 3;
}

被 GCC 4.7 的 OpenMP 处理器降低为:

#pragma omp critical (my_crit)
__builtin_GOMP_critical_name_start (&.gomp_critical_user_my_crit);
try
  {
    D.20639 = __cxa_allocate_exception (4);
    try
      {
        MEM[(int *)D.20639] = 3;
      }
    catch
      {
        __cxa_free_exception (D.20639);
      }
    __cxa_throw (D.20639, &_ZTIi, 0B);
  }
catch
  {
    <<<eh_must_not_throw (terminate)>>>
  }
__builtin_GOMP_critical_name_end (&.gomp_critical_user_my_crit);

达到隐式内置的 catch-all 处理程序<<<eh_must_not_throw (terminate)>>>会导致非常不优雅的终止:

terminate called after throwing an instance of 'int'
Abort trap: 6

try/catch无论外部构造是否存在,都会插入隐式try/catch,即异常永远不会离开该critical部分。

parallelOpenMP 标准规定,如果在大多数 OpenMP 构造( 、sectionmastersingleforcritical、等)中引发异常,则task必须在同一构造中恢复执行,并且同一线程必须捕获异常。违反此限制会导致不符合标准的 OpenMP 代码,并通过在所有此类构造中g++插入try/catch带有终止处理程序的块来简单地强制符合标准。

至于return存在语句时的错误,OpenMP 将 C/C++ 中的结构化块定义为:

对于 C/C++,一个可执行语句,可能是复合语句,顶部有一个入口,底部有一个出口,或者是一个 OpenMP 结构。

还有(对于所有语言):

退出点不能是结构化块的分支。

显然return构成了块的一个分支,不同于简单的块底部的下降。

于 2012-12-01T22:13:00.140 回答