OpenMP 我是否有竞争条件或错误共享?



我正在尝试编写矩阵乘法的代码。就我对OMP和pararel编程的理解而言,这段代码可能会受到竞争条件的影响。

#pragma omp parallel
#pragma omp for
for (int k = 0; k < size; k++){
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
c[i][j] += a[i][k] * b[k][j];
}}}

如果我在写入c矩阵之前放入#pragma omp atomic,或者通过将private(I(添加到第二个#pragma,我会去掉它吗?还有可能让这个代码虚假共享免费吗?如果是,如何?

当两个或多个线程访问同一内存位置,并且其中至少有一个线程正在写入时,就会出现争用条件。c[i][j] +=...行可能会导致代码中的数据争用。解决方案是重新排序嵌套循环(使用ijk的顺序(,您可以引入一个临时变量来计算点积:

#pragma omp parallel for
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
double tmp=0; // change its type as needed
for (int k = 0; k < size; k++){
tmp += a[i][k] * b[k][j];
}
c[i][j] = tmp;  //note that += was used in your original code
}
}

注意,如果计算矩阵b的转置,代码会更快。有关更多详细信息,请阅读本文。

更新:

如果您需要维护循环的顺序,有两种可能性(但这些解决方案可能比串行代码慢(:

  1. 使用原子操作(即#pragma omp atomic(。在这种情况下,虚假共享也可能是一个问题。

  2. 如果你的堆栈足够大,可以存储所有线程的矩阵,那么更好的选择是使用reduction:#pragma omp parallel for reduction(+:c[:size][:size])(另一种选择是手动进行reduction。在这种情况下,你可以在堆上分配用于reduction的矩阵。(

最新更新