并发 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 子句了。还有其他显着差异吗?
默认情况下不提供同步机制。但是 OpenMP 提供了明确使用此类机制的可能性。为此目的使用 #pragma omp atomic
、#pragma omp atomic read
、#pragma omp atomic write
。使用关键部分的另一个选项:#pragma omp critical
- 更通用和更强大的选项,但并非总是必需的。
通过不同的变量访问相同的内存位置不会改变并发访问的任何内容。你应该使用原子来提供保证。
如果在 pragma omp parallel
中声明变量 - 它们对于线程来说是私有的。有关详细信息,请参阅 this and this 个帖子。
此外,如果您使用的是 C++11,则可以使用 std::atomic
个变量。
关于 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 子句了。还有其他显着差异吗?
默认情况下不提供同步机制。但是 OpenMP 提供了明确使用此类机制的可能性。为此目的使用
#pragma omp atomic
、#pragma omp atomic read
、#pragma omp atomic write
。使用关键部分的另一个选项:#pragma omp critical
- 更通用和更强大的选项,但并非总是必需的。通过不同的变量访问相同的内存位置不会改变并发访问的任何内容。你应该使用原子来提供保证。
如果在
pragma omp parallel
中声明变量 - 它们对于线程来说是私有的。有关详细信息,请参阅 this and this 个帖子。
此外,如果您使用的是 C++11,则可以使用 std::atomic
个变量。