2011-12-16 150 views
1

我想写一个函数,它使用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()第一个呼叫工作得很好:ms尽可能地获得值1,但是在并行区域内第二次调用func()确实会创建嵌套并行(即每个线程有16个团队),尽管这被抑制了。那就是omp masteromp 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(); 
} 

解决这个问题,但是这需要一个附加功能进行定义等是否有可能在单个函数内做到这一点(和不重复的代码) ?

回答

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的内部,即使它不是活动的。

就我个人而言,我从来没有遇到过我希望它的行为不同的情况(这会违背信息隐藏等),所以也许你应该告诉我们更多关于你想要获得更好答案的内容。

0

我看了一下openMP标准。 if条款实际上有些误导性地提出,因为#pragma omp parallel指令不是有条件的(正如我原先的想法)。相反,if子句可能会将线程数限制为1,从而抑制并行化。

但是,这意味着omp singleomp master不能用于线程安全每进程一次写入全局共享变量。

+0

是的,它确实意味着它并不适用于此,因为通常不能保证(信息隐藏和全部)在外层没有嵌套并行性。对共享变量进行访问threadsafe更像是互斥体的用例(omp中的锁)。你的描述你想如何工作听起来没有什么用处(如果有多个线程调用`do_func`,你只需要其中一个线程(因此调用)写入全局变量?我不知道你的具体情况,但这听起来不太有用。 – Grizzly 2011-12-23 02:14:03