并行化矩阵按行和按行使用OpenMP按行计算

时间:2014-04-24 18:56:57

标签: c parallel-processing openmp

对于我的一些家庭作业,我需要用矢量实现矩阵的乘法,按行和列并行化。我确实理解行版本,但我在列版本中有点困惑。

假设我们有以下数据:

Matix times vector

行版的代码:

#pragma omp parallel default(none) shared(i,v2,v1,matrix,tam) private(j)
  {
#pragma omp for
    for (i = 0; i < tam; i++)
      for (j = 0; j < tam; j++){
//        printf("Hebra %d hizo %d,%d\n", omp_get_thread_num(), i, j);
        v2[i] += matrix[i][j] * v1[j];
      }
  }

这里的计算是正确的,结果是正确的。

列版本:

#pragma omp parallel default(none) shared(j,v2,v1,matrix,tam) private(i)
  {
    for (i = 0; i < tam; i++)
#pragma omp for
      for (j = 0; j < tam; j++) {
//            printf("Hebra %d hizo %d,%d\n", omp_get_thread_num(), i, j);
        v2[i] += matrix[i][j] * v1[j];
      }
  }

这里,由于并行化的完成方式,每次执行的结果都会有所不同,具体取决于执行每列的线程。但它发生了一些有趣的事情(我认为是因为编译器优化)如果我取消注释printf然后结果与行版本完全相同,因此,更正,例如:

Thread 0 did 0,0
Thread 2 did 0,2
Thread 1 did 0,1
Thread 2 did 1,2
Thread 1 did 1,1
Thread 0 did 1,0
Thread 2 did 2,2
Thread 1 did 2,1
Thread 0 did 2,0

 2.000000  3.000000  4.000000 
 3.000000  4.000000  5.000000 
 4.000000  5.000000  6.000000 


V2:
20.000000, 26.000000, 32.000000,

是对的,但如果我删除了printf:

V2:
18.000000, 11.000000, 28.000000,

我应该使用什么样的机制来使列版本正确?

注意:我更关心的是解释而不是您可能发布的代码作为答案,因为我真正想要的是了解列版本中出了什么问题。

修改

我找到了一种摆脱Z boson在他的回答中提出的私人向量的方法。我已经用变量替换了该向量,这里是代码:

    #pragma omp parallel
      {
        double sLocal = 0;
        int i, j;
        for (i = 0; i < tam; i++) {
    #pragma omp for
          for (j = 0; j < tam; j++) {
            sLocal += matrix[i][j] * v1[j];
          }
    #pragma omp critical
          {
            v2[i] += sLocal;
            sLocal = 0;
          }
        }
      }

2 个答案:

答案 0 :(得分:5)

我不知道你的家庭作业究竟是什么意思,通过行和列并行化,但我知道为什么你的代码不起作用。当您写信至v2[i]时,您会遇到竞争条件。您可以通过创建v2[i]的私有版本,并行填充它们,然后将它们与关键部分合并来修复它。

#pragma omp parallel
{
    float v2_private[tam] = {};
    int i,j;
    for (i = 0; i < tam; i++) {
        #pragma omp for
        for (j = 0; j < tam; j++) {
            v2_private[i] += matrix[i][j] * v1[j];
        }
    }
    #pragma omp critical
    {
        for(i=0; i<tam; i++) v2[i] += v2_private[i];
    }
}

我测试了这个。您可以在此处查看结果http://coliru.stacked-crooked.com/a/5ad4153f9579304d

请注意,我没有明确定义任何共享或私有。没有必要这样做。有些人认为你应该明确定义一切。我个人认为恰恰相反。通过在并行部分中定义ij(以及v2_private),它们将变为私有。

答案 1 :(得分:1)

我会说行版本更有效,因为每个线程不需要私有存储,也不需要使用临界区或互斥锁进行部分求和。 代码也简单多了:

#pragma omp parallel for
for (int i = 0; i < tam; i++) {
    for (int j = 0; j < tam; j++) {
        v2[i] += matrix[i][j] * v1[j];
    }
}