【问题标题】:When should I overlook critical sections and when nowait is needed ? OpenMp我什么时候应该忽略关键部分,什么时候需要 nowait ? OpenMp
【发布时间】:2021-07-25 22:36:00
【问题描述】:

我正在研究 OpenMP,我有一些问题我相信会澄清我的想法。

我有一个矩阵乘法 A*B 的小例子,其中 A、B、C 是全局变量。我知道我们如何可以一次并行化 for 循环或同时并行化折叠,但我的问题是:

如果我使用 #pragma omp for 在哪个循环中,我应该忽略 check1 中的关键部分,因为 C 是一个全局变量,并且我应该在哪个循环中使用关键字 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
     };

我的方法

#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. 一个:我把“nowait”放在那里是因为代码运行得更快,我不知道原因或者我是否做出了正确的决定
  2. 两个:我使用关键部分来思考如何使用线程构建它。

所以让我们说这是正确的,如果并行化第二个 for 循环或第三个循环,我是否需要这些东西?如果有人可以在我需要添加关键部分时向我解释,或者如果我一次并行化这个嵌套的 for 循环,我将不胜感激!

【问题讨论】:

    标签: c multithreading performance parallel-processing openmp


    【解决方案1】:

    在您的示例中,您既不需要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 em> 只需将它们设为私有,例如,如下所示:

     #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]
    

    一个:我把“nowait”放在那里是因为代码运行得更快,我没有 知道原因或者我是否做出了正确的决定

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

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

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

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

    因此,假设这是正确的,那么并行化 第二个 for 循环或第三个循环我是否需要这些东西?

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

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

    【讨论】:

      猜你喜欢
      • 2016-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      • 2021-09-07
      • 2012-12-23
      相关资源
      最近更新 更多