我想编写一个使用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()
的第一次调用工作正常:m
和s
按原样获取值1,但是从并行区域内第二次调用func()
确实创建了嵌套并行性(16个团队,每个团队1个线程),尽管这被抑制了。那就是omp master
和omp 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();
}
但是这需要定义一个额外的功能等。是否可以在单个函数中执行此操作(并且不重复代码)?
答案 0 :(得分:2)
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
内,即使它不活跃。
就我个人而言,我从未遇到过一种情况,我希望它的行为方式不同(这会违背信息隐藏等),所以也许你应该多告诉我们你想要达到的目标,以获得更好的答案。 / p>
答案 1 :(得分:0)
我看了一下openMP标准。 if
子句实际上有点误导,因为#pragma omp parallel
指令不是有条件的(正如我原先认为的那样)。相反,if
子句可以将线程数限制为1,从而抑制并行化。
但是,这意味着omp single
或omp master
不能用于线程安全的每进程一次写入全局共享变量。