何时需要减少?

3
我编写了一段读取矩阵并对其值进行求和的代码......但我的问题是,由于我尝试以不同的方式进行Pragma,我发现reduction(+:sum)可能是不必要的,但是,我只是不知道为什么,可能我错过了在此情况下减少系统的实际含义。这是另一种选择:#pragma omp parallel for private(i, j) reduction(+:sum) 以下是代码:
#include <stdio.h>
#include <math.h>
#include <omp.h>
#include <unistd.h>


int main ()
{

    printf("===MATRIX SUM===\n");
    printf("N ROWS: ");
    int i1; scanf("%d",&i1);
    printf("M COLUMNS: ");
    int j1; scanf("%d",&j1);
    int matrixA[i1][j1];

    int i, j;

    for(i = 0; i < i1; i++){
        for (j = 0; j < j1; j++){
            scanf("%d",&matriuA[i][j]);
        }
    }

    printf("\nMATRIX A: \n");
    for (i = 0; i < i1; i++){
        for (j = 0; j < j1; j++){
            printf("%d ", matrixA[i][j]);
        }
        printf("\n");
    }
    int sum = 0;
    #pragma omp parallel for private(i, j)
        for (i = 0; i < i1; i++)
            for (j = 0; j < j1; j++){
                sum += matrixA[i][j];
           }


    printf("\nTHE RESULT IS: %d", sum);

    return 0;
}

我有一个问题想请教,是否有更好的方法来减少pragma,因为我读到这是最有效的方法。


你应该同时放置reduction和sum+=..,因为你希望单个OpenMP线程执行sum+=...并对每个OpenMP线程的sum变量进行归约。 - yakoudbz
如果我理解你所说的效率,你希望在每个线程内使用SIMD约简以及外部循环约简,即使这需要单独命名内部和外部约简变量。 - tim18
1个回答

5
您发布的代码没有缩减子句是不正确的
sum += matrixA[i][j];

在多个线程并行执行时,会导致经典的竞态条件。sum是一个共享变量,但sum += ...不是一种原子操作。

(sum is initially 0, all matrix elements 1)
Thread 1                     |  Thread 2
-----------------------------------------------------------
tmp = sum + matrix[0][0] = 1 |
                             | tmp = sum + matrix[1][0] = 1
sum = tmp = 1                |
                             | sum = tmp = 1 (instead of 2)

减少修复了这个问题。通过减少,循环将处理隐式的线程本地副本sum变量。在该区域结束时,原始的sum变量将设置为所有线程本地副本的总和(以正确的方式,没有竞争条件)。另一种解决方法是将sum += ...标记为原子操作或关键部分。然而,这会带来显著的性能惩罚。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接