在omp关键节内引发C++异常

Throwing a C++ exception inside an omp critical section

本文关键字:C++ 异常 omp      更新时间:2023-10-16

我想知道在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;
...       
}

那么,为什么在关键部分留下一个异常是可以的,而在关键部分保留一个返回语句是不可以的呢?

不,在关键部分保留异常是不可以的。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部分。

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

对于出现return语句时的错误,OpenMP将C/C++中的结构化块定义为:

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

以及(适用于所有语言):

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

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