什么时候应该忽略关键部分,什么时候需要 nowait ?打开MP

When should I overlook critical sections and when nowait is needed ? OpenMp

我正在研究 OpenMP,我有一些问题相信可以理清思路。

我有一个矩阵乘法 A*B 的小例子,其中 A、B、C 是全局变量。我知道我们如何并行化 for 循环一次一个或两个与崩溃一起并行化,但我的问题是:

Ιn which loop if I use #pragma omp for should I overlook the critical section in check1 where we need to add there because C is a global variable and also in which loop 我应该使用关键字 nowait 来避免循环中出现障碍,因为我知道 #pragma omp for 它会自动拥有它。当我尝试编写这个嵌套的 for 循环时,我正在做这个:my_approach

int i,j,sum;
for(int i=0;i<N;i++) # loop1
    for(j=0;j<N;j++){ #loop2
         for(k=sum=0;k<N;k++) #loop3
             sum += A[i][j]*B[k][J]
         C[i][j] = sum  # check1
     };

my_approach

#pragma omp parallel num_threads(4)
{
    #pragma omp for schedule(static) nowait // **one**
     for(int i=0;i<N;i++) # loop1
        for(j=0;j<N;j++){ #loop2
             for(k=sum=0;k<N;k++) #loop3
                 sum += A[i][j]*B[k][J]
             #pragma omp critical //  **two**
             C[i][j] = sum  # check1
         };
}
  1. one:我把“nowait”放在那里是因为代码运行得更快,我不知道原因或者我是否做出了正确的决定
  2. two :我使用临界区思考如何用线程构建它。

所以我们可以说这是正确的关于并行化第二个 for 循环或第三个循环我是否需要这些东西呢?如果有人可以向我解释我何时需要添加临界区或等待我一次并行化这个嵌套的 for 循环,我将不胜感激!

在您的示例中,您既不需要 nowait 也不需要 critical:

 #pragma omp parallel for schedule(static) num_threads(4) // **one**
 for(int i=0;i<N;i++) # loop1
    for(j=0;j<N;j++){ #loop2
         for(k=0;k < N;k++) #loop3
             C[i][j] += A[i][j]*B[k][J]
  

没有竞争条件,在更新全局矩阵C期间,每个线程更新该矩阵的不同位置。但是,您有一个不同的 race-condition,即在变量 jk 的更新期间,因为两者在线程之间共享,以修复此 race-condition 将它们设为私有即可,例如,如下:

 #pragma omp parallel for schedule(static) num_threads(4) // **one**
 for(int i=0;i<N;i++) # loop1
    for(int j=0;j<N;j++){ #loop2
         for(int k=0;k < N;k++) #loop3
             C[i][j] += A[i][j]*B[k][J]

one : I put "nowait" there because code runs faster with that , I dont know the reason or if I am making the right decision

嗯,你不应该 盲目地 删除它而没有充分的理由。在这里您可以安全地删除,因为 1) 在并行 for 和并行区域之间没有使用代码,2) 并行区域也有一个隐式屏障。

#pragma omp parallel num_threads(4)
{
    #pragma omp for schedule(static) nowait // **one**
     ...
   // There no code here
} // <-- implicit barrier

尽管如此,在您的情况下,您可以将两个编译指示合并为一个并删除 nowait 子句:

#pragma omp parallel for schedule(static) num_threads(4)

So let's say that this is right what about with parallelizing the second for loop or third do I need those things or not ?

通用答案视情况而定。这取决于太多因素,但通常你应该从最外层的循环开始,因为那些会产生最高粒度的任务,但这同样取决于具体情况。尽管如此,在您的具体示例中,您可以并行化最外层的循环。

您可以尝试并行化嵌套循环,看看是否有任何性能提升。通过并行化最外层循环与并行化前两个最外层循环进行测试,并检查您是否获得了任何性能提升。