我正在尝试编写矩阵乘法的代码。就我对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] +=...
行可能会导致代码中的数据争用。解决方案是重新排序嵌套循环(使用i
、j
、k
的顺序(,您可以引入一个临时变量来计算点积:
#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
的转置,代码会更快。有关更多详细信息,请阅读本文。
更新:
如果您需要维护循环的顺序,有两种可能性(但这些解决方案可能比串行代码慢(:
使用原子操作(即
#pragma omp atomic
(。在这种情况下,虚假共享也可能是一个问题。如果你的堆栈足够大,可以存储所有线程的矩阵,那么更好的选择是使用reduction:
#pragma omp parallel for reduction(+:c[:size][:size])
(另一种选择是手动进行reduction。在这种情况下,你可以在堆上分配用于reduction的矩阵。(