C 如何在OpenMP中对此进行并行处理

C 如何在OpenMP中对此进行并行处理,c,matrix,parallel-processing,openmp,C,Matrix,Parallel Processing,Openmp,我知道OpenMP的基础知识,我知道为了并行化一个应用程序,它的迭代不能依赖于以前的迭代。也可以使用约化,但它们只支持基本运算符,如+、-、/、*、&&&、| | 我怎样才能把它做成平行的 for (i = 1; i < n; ++i) { for (j = 1; j < n; ++j) { // stanga if (res[i][j - 1] != res[i][j]) { cmin2[i][j][0] = min(

我知道OpenMP的基础知识,我知道为了并行化一个应用程序,它的迭代不能依赖于以前的迭代。也可以使用约化,但它们只支持基本运算符,如+、-、/、*、&&&、| |

我怎样才能把它做成平行的

for (i = 1; i < n; ++i) {
    for (j = 1; j < n; ++j) {
        // stanga
        if (res[i][j - 1] != res[i][j]) {
            cmin2[i][j][0] = min(cmin2_res[i][j - 1][0] + 1, cmin[i][j][0]);
            cmin2_res[i][j][0] = min(cmin2[i][j - 1][0] + 1, cmin_res[i][j][0]);
         } else {
            cmin2[i][j][0] = min(cmin2[i][j - 1][0] + 1, cmin[i][j][0]);
            cmin2_res[i][j][0] = min(cmin2_res[i][j - 1][0] + 1, cmin_res[i][j][0]);
         }
         // sus
         if (res[i - 1][j] != res[i][j]) {
             cmin2[i][j][0] = min3(cmin2[i][j][0], cmin2_res[i - 1][j][0] + 1, cmin[i][j][1]);
             cmin2_res[i][j][0] = min3(cmin2_res[i][j][0], cmin2[i - 1][j][0] + 1, cmin_res[i][j][1]);
         } else {
             cmin2[i][j][0] = min3(cmin2[i][j][0], cmin2[i - 1][j][0] + 1, cmin[i][j][1]);
             cmin2_res[i][j][0] = min3(cmin2_res[i][j][0], cmin2_res[i - 1][j][0] + 1, cmin_res[i][j][1]);
         }
     }
 }
(i=1;i{ 对于(j=1;j 我的问题是如何将其分解,以便能够并行运行(如果可能的话,还可以使用缩减)

问题是,在每次迭代中,操作必须按照这个顺序进行,因为我还有3组类似的for


p.S.min和min3是宏。

有一种蛮力方式来做你想做的事情,但是更好的并行化需要更多关于你想从例程中得到什么的输入

在i-j空间中,循环中的数据依赖项如下所示:

     i →
  ..........
j .....1....
↓ ....12....
  ...123....
其中,点3处的值取决于点2s处的值,而点1处的值取决于点1处的值,等等。由于这种对角结构,您可以对循环进行重新排序,以对角方式穿过网格,例如,第一次迭代超过(0,1)、(1,0),然后超过(0,2)、(1,1)、(2,0),等等。问题的简化版本如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>

int **int2darray(int n, int m);
void free2darray(int **array);
void init2darray(int **array, int n, int m);
void tick(struct timeval *timer);
double tock(struct timeval *timer);

int main(int argc, char **argv) {

    const int N=10000;
    int **serialarr, **omparr;

    struct timeval serialtimer, omptimer;
    double serialtime, omptime;

    serialarr = int2darray(N,N);
    omparr    = int2darray(N,N);

    init2darray(serialarr, N, N);
    init2darray(omparr,    N, N);

    /* serial calculation */
    tick(&serialtimer);
    for (int i=1; i<N; i++)
        for (int j=1; j<N; j++)
            serialarr[i][j] = serialarr[i-1][j] + serialarr[i][j-1];
    serialtime = tock(&serialtimer);

    /* omp */
    tick(&omptimer);
    #pragma omp parallel shared(omparr) default(none)
    {
        for (int ipj=1; ipj<=N; ipj++) {
            #pragma omp for
            for (int j=1; j<ipj; j++) {
                int i = ipj - j;
                omparr[i][j] = omparr[i-1][j] + omparr[i][j-1];
            }
        }
        for (int ipj=N+1; ipj<2*N-1; ipj++) {
            #pragma omp for
            for (int j=ipj-N+1; j<N; j++) {
                int i = ipj - j;
                omparr[i][j] = omparr[i-1][j] + omparr[i][j-1];
            }
        }
    }
    omptime = tock(&omptimer);

    /* compare results */
    int abserr = 0;
    for (int i=0; i<N; i++)
        for (int j=0; j<N; j++)
            abserr += abs(omparr[i][j] - serialarr[i][j]);

    printf("Difference between serial and OMP array: %d\n", abserr);
    printf("Serial time = %lf\n", serialtime);
    printf("OMP time    = %lf\n", omptime);

    free2darray(omparr);
    free2darray(serialarr);
    return 0;
}


int **int2darray(int n, int m) {
    int *data = malloc(n*m*sizeof(int));
    int **array = malloc(n*sizeof(int*));
    for (int i=0; i<n; i++)
        array[i] = &(data[i*m]);

    return array;
}

void free2darray(int **array) {
    free(array[0]);
    free(array);
}

void init2darray(int **array, int n, int m) {
    for (int i=0; i<n; i++)
        for (int j=0; j<m; j++)
            array[i][j] = i*m+j;
}

void tick(struct timeval *timer) {
    gettimeofday(timer, NULL);
}

double tock(struct timeval *timer) {
    struct timeval now;
    gettimeofday(&now, NULL);
    return (now.tv_usec-timer->tv_usec)/1.0e6 + (now.tv_sec - timer->tv_sec);
}
您会注意到,即使使用较大的N,加速率也相当低,因为每次迭代的计算量很小,内部循环是并行的,我们以一种奇怪的、不利于缓存的顺序遍历内存


上面提到的一些问题可能是可以解决的,但如果你能更多地了解你想做的事情,那会有更多的帮助;例如,您关心cmin2_res阵列,还是它们只是中间产品?换句话说,你想计算什么?

i处的结果,j取决于i-1和j-1处的结果。您可能需要更改算法以使其能够并行运行。试一试纸上的2x2案例,看看你不能计算(0,0),(0,1),。。在没有输入数据限制的情况下高效地并行处理值。我知道这一点,问题是如何打破for,以便并行处理。非常感谢!我现在正试着用这个。我还有3组这样的人。我保留cmin2和cmin2_res,因为对于矩阵中的每个元素,我必须从cmin2和cmin2_res计算最小值
$ gcc -fopenmp -Wall -O2 loops.c -o loops -std=c99 
$ export OMP_NUM_THREADS=8
$ ./loops
Difference between serial and OMP array: 0
Serial time = 0.246649
OMP time    = 0.174936