我目前正在使用OpenMP进行矩阵计算。我的代码中有几个循环,而是调用每个循环#pragma omp parallel for [...](创建所有线程并在之后销毁它们)我想在开头创建所有这些,并且在程序结束时删除它们以避免开销。 我想要这样的东西:
#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
它没有编译,我从gcc得到这个错误:“工作共享区域可能没有紧密嵌套在工作共享,关键,有序,主要或显式任务区域内。”
我知道它肯定来自“错误”的嵌套,但我无法理解为什么它不起作用。我需要在并行区域之前添加屏障吗?我有点迷茫,不知道如何解决它。
提前感谢您的帮助。 欢呼声。
答案 0 :(得分:3)
在最后的代码大纲中,您声明了一个并行区域,在其中使用master指令来确保只有主线程执行一个块,并且在主块内部尝试并行化所有线程的循环。您声称知道编译器错误是由不正确的嵌套引起的,但想知道为什么它不起作用。
它不起作用,因为将工作分配给只有一个线程将执行的代码区域内的多个线程没有任何意义。
您的第一个伪代码更好,但您可能希望像这样扩展它:
#pragma omp parallel
{
#pragma omp for[...]
for(...)
#pragma omp single
{ ... }
#pragma omp for[...]
for(...)
}
single
指令确保它所包含的代码块仅由一个线程执行。与master
指令不同single
也意味着退出时的障碍;您可以使用nowait
子句更改此行为。
答案 1 :(得分:3)
大多数OpenMP运行时都没有“创建所有线程并在之后立即销毁它们”。线程在第一个OpenMP部分的开头创建,并在程序终止时被销毁(至少是英特尔的OpenMP实现方式)。使用一个大的并行区域而不是几个较小的并行区域没有性能优势。
英特尔的运行时(开源,可以找到here)具有控制线程在用完工作时所执行操作的选项。默认情况下,它们会旋转一段时间(如果程序立即启动一个新的并行部分),那么它们就会让自己进入睡眠状态。如果执行睡眠,则需要更长时间才能启动下一个并行部分,但这取决于区域之间的时间,而不是语法。