2013-11-21 88 views
6

我目前正在使用OpenMP进行矩阵计算。我在我的代码中有几个循环,而是调用每个循环#pragma omp parallel for [...](创建所有线程并在之后立即销毁它们),我想在开始时创建它们,并且在程序结束时删除它们以避免开销。 我想是这样的:如何使用OpenMP在并行循环中嵌套并行循环

#pragma omp parallel 
{ 
    #pragma omp for[...] 
    for(...) 

    #pragma omp for[...] 
    for(...) 
} 

的问题是,我有一些部分的那些必须由只有一个线程来执行,但在一个循环,其中包含循环那些必须并行执行。这是它的外观:

//have to be execute by only one thread 
int a=0,b=0,c=0; 
for(a ; a<5 ; a++) 
{ 

    //some stuff 

    //loops which have to be parallelize 
    #pragma omp parallel for private(b,c) schedule(static) collapse(2) 
    for (b=0 ; b<8 ; b++); 
     for(c=0 ; c<10 ; c++) 
     { 
      //some other stuff 
     } 

    //end of the parallel zone 
    //stuff to be execute by only one thread 

} 

(环路界限是相当小的在我的例子在我的计划可以去到20.000迭代次数...。) 一个我的第一个想法的是做这样的事情:

//have to be execute by only one thread 
#pragma omp parallel //creating all the threads at the beginning 
{ 
    #pragma omp master //or single 
    {   
     int a=0,b=0,c=0; 
     for(a ; a<5 ; a++) 
     { 

      //some stuff 

      //loops which have to be parallelize 
      #pragma omp for private(b,c) schedule(static) collapse(2) 
      for (b=0 ; b<8 ; b++); 
       for(c=0 ; c<10 ; c++) 
       { 
        //some other stuff 
       } 

      //end of the parallel zone 
      //stuff to be execute by only one thread 

     } 
    } 
} //deleting all the threads 

它不能编译,我得到这个错误来自海湾合作委员会:“工作共享区域不可以紧密嵌套在工作共享,临界,有序,主要的或显式的任务区域内”。

我知道它一定来自于“错误”的嵌套,但我不明白为什么这是行不通的。我需要在并行区域之前添加屏障吗?我有点失落,不知道如何解决它。

非常感谢您的帮助。 干杯。

回答

3

在过去的代码的概述声明并行区域,里面使用的主指令,以确保只有主线程执行块,和主块试图parallelise所有线程在一个循环中。你声称知道编译错误是由不正确的嵌套造成的,但是奇怪为什么它不起作用。

它不起作用,因为的代码只有一个线程将执行没有任何意义的区域内分配工作到多线程。

你的第一个伪代码是好,但你可能要像这样延伸:

#pragma omp parallel 
{ 
    #pragma omp for[...] 
    for(...) 

    #pragma omp single 
    { ... } 

    #pragma omp for[...] 
    for(...) 
} 

single指令确保代码是封闭块只能由一个线程执行。不同于master指令single也意味着出口处的障碍;您可以使用nowait子句更改此行为。

+0

谢谢你的回答。我将尝试重新排列我的代码,以使结构更简单并行。 – user3014051

3

OpenMP的大部分运行时间不“创建的所有线程和右后消灭他们”。线程在第一个OpenMP部分的开始处创建,并在程序终止时销毁(至少英特尔的OpenMP实现如此)。使用一个大平行区域而不是几个小平行区域没有性能优势。

英特尔的运行时(这是开源的,可以发现here)的选项来控制,当他们用完工作线程怎样做。默认情况下,他们会旋转一段时间(如果程序立即启动一个新的平行部分),然后他们会自己睡觉。如果确实睡眠了,那么为下一个并行部分启动它需要更长的时间,但这取决于区域之间的时间,而不是语法。