并发 read/write 到 OpenMp 中的共享变量

Concurrent read/write to shared variables in OpenMp

关于 OpenMp,我基本上有三个问题。

Q1。 OpenMp 是否提供共享变量的互斥?考虑以下具有三个嵌套循环的简单矩阵乘法代码,使用 C++ 中的 OpenMp 进行并行化。这里 A、B 和 C 是动态分配的 space double** 类型的变量。线程计数被适当地分配了一个值。

#pragma omp parallel
{
 int tid = omp_get_thread_num();
 int fraction = (n/threadCount);
 int start = tid * fraction;
 int end = (tid+1) * fraction;

    for (int start = 0; i < end; i++)
    {
        for (int j = 0; j < N; j++)
        {
            C[i][j] = 0;

            for (int k = 0; k < N; k++)
                C[i][j] += A[i][k] * B[k][j];
        }
     }
}

这里的问题是,从A和B读取和向C写入的互斥是不必要的。但是如果因为A、B、C上的mutex而产生了额外的开销,那么解除A、B、C的mutex是有利的。如何实现?

Q2。 考虑在上面的代码中引入两个私有变量tempA和tempB,如下。

double **tempA, **tempB;

#pragma omp parallel private(tempA, tempB)
{
 int tid = omp_get_thread_num();
 int fraction = (n/threadCount);
 int start = tid * fraction;
 int end = (tid+1) * fraction;
 tempA = A;
 tempB = B;

    for (int start = 0; i < end; i++)
    {
        for (int j = 0; j < N; j++)
        {
            C[i][j] = 0;

            for (int k = 0; k < N; k++)
                C[i][j] += tempA[i][k] * tempB[k][j];
        }
     }
}

这个策略会不会在计算中解除 A 和 B 的互斥量?我的意思是,尽管所有线程都访问相同的位置(由 A 和 tempA,以及 B 和 tempB 引用),但它们通过不同的局部变量引用它们。

Q3。 另外,我想知道在并行代码段内声明变量 tempA 和 tempB 与在外部声明它们的区别。当然,这样我们就不需要指令中的 private 子句了。还有其他显着差异吗?

  1. 默认情况下不提供同步机制。但是 OpenMP 提供了明确使用此类机制的可能性。为此目的使用 #pragma omp atomic#pragma omp atomic read#pragma omp atomic write。使用关键部分的另一个选项:#pragma omp critical - 更通用和更强大的选项,但并非总是必需的。

  2. 通过不同的变量访问相同的内存位置不会改变并发访问的任何内容。你应该使用原子来提供保证。

  3. 如果在 pragma omp parallel 中声明变量 - 它们对于线程来说是私有的。有关详细信息,请参阅 this and this 个帖子。

此外,如果您使用的是 C++11,则可以使用 std::atomic 个变量。