如何在OpenMP并行区域内找到是否
How to find out if inside an openMP parallel region?
在我的代码中,我想避免在任何OpenMP并行区域内抛出异常(因为如果未在同一区域内捕获,则会导致未手动异常)。为此,我尝试使用OpenMP运行时库函数
omp_in_parallel();
决定是抛出异常还是写出错误消息并终止。但是,在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
}
}
不会导致错误:'3',但在扔出'int'aport'aport 的实例后终止了。
。这是正确的行为(omp_in_parallel()
)吗?(OpenMP标准似乎很模糊)还是GCC中的错误?如何修复上述do_something()
代码,以便仅在不在平行区域中抛出?
OpenMP标准指出,omp_in_parallel()
返回 true 时,仅当包含parallel
区域处于活动状态时。活动的parallel
区域被定义为由由组成的团队执行的一个多个线程。在您的情况下,由于只有一个线程,因此您有一个不活动的平行区域。因此,omp_in_parallel()
返回false
,并且执行throw
。之所以出错,是因为OpenMP标准将异常限制在同一并行区域和线程:
在
parallel
区域内执行的throw
必须导致执行以在同一parallel
区域内恢复,并且抛出异常的同一线程必须捕获它。
这使您的代码不合格,因为您让异常通过并通过并行区域进行。Intel OpenMP运行时发出了相同的错误,因此它不是GCC特定的行为。
实际上发生的是GCC通过将代码包裹在try/catch
块中使用CATCH-ALL例外过滤器来转换OpenMP区域:
#pragma omp parallel [child fn: main.omp_fn.0 (???)]
{
try
{
do_something ();
}
catch
{
<<<eh_filter (NULL)>>>
{
terminate ();
}
}
#pragma omp return
}
是终止消息的责任。
要解决这一问题,整个try/catch
块应为内部 不反之亦然:
# pragma omp parallel
{
try {
do_something();
} catch(int e) {
std::cerr<<"error: '"<<e<<"'n"; // never gets here
}
}
(添加了额外的块以使Intel C 编译器感到高兴;对于GCC来说,这不是必需的)
这将按预期输出error: '3'
。
编辑:有趣的是,您的异常处理程序甚至没有将其纳入最后的二进制文件。即使考虑到GCC的默认优化级别(即使用g++ -fopenmp -o prog prog.cc
编译),冗余消除器也能够检测到您的异常处理程序将由于隐含的内部异常处理程序而无法达到您的异常处理程序,因此您的处理程序被删除。然后,编译器发现隐式终止处理程序也是冗余的,因为整个过程中已经有一个顶级异常处理程序,可以执行相同的操作(CALL terminate()
),从而消除了隐式。最终代码是如此精简和卑鄙 - 完全没有例外处理程序:
;; 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
}
一个人可以爱上-fdump-tree-all
GCC选项。
编辑:关于如何修复do_something()
的问题 - 使用omp_get_level()
代替omp_in_parallel()
:
void do_something()
{
if(omp_get_level() == 0)
throw 3;
}
omp_get_level()
返回包含呼叫的parallel
区域的嵌套级别,无论它们是否处于活动状态。
- 有没有一种优雅而快速的方法来测试整数中的 1 位是否位于连续区域
- 我的主窗口在创建时或单击更新区域时是否会收到编辑控件?
- 是否有任何区域设置会影响宽字符编码?
- 是否可以在并行区域中为共享 2D 数组创建选定元素的线程本地副本?(共享,私有,障碍:OPenMP)
- 是否有一对正宽度和长度值将返回负区域?
- OpenglGL - 如何检查光标是否与对象区域重合?
- 多个线程/进程是否可以在不同步的情况下同时从/写入文件的非重叠区域?
- 区域设置是否有定义负号的方面?
- 如果不在派生类实现中执行此操作,"basic_streambuf"是否会创建自己的获取/放置区域?
- 从多个线程写入内存区域是否会导致争用?
- std::string 的运算符<是否应该受到当前区域设置的影响?
- 是否有有效的标准算法来栅格化面,包括其内部区域
- Win32 中是否有一条消息或通知来检测用户何时更改区域设置?
- 如何检查鼠标是否在FreeGlut的三角区域内单击
- 如何在OpenMP并行区域内找到是否
- 如何检查迭代器是否形成连续的内存区域
- 使用UTC来回转换日期以忽略DST但仍使用当前用户的有效区域设置是否安全
- #if 条件区域是否可以跨越包含文件边界
- 字符串流插入器是否使用当前区域设置
- std::ctype 是否总是按"C"区域设置对字符进行分类?