Parallele kumulative (Präfix-) Summen in OpenMP: Kommunizieren von Werten zwischen Threads

Angenommen, ich habe eine Funktionf(i) das hängt von einem Index abi (unter anderem Werte, die nicht vorberechnet werden können). Ich möchte ein Array füllena damita[n] = sum(f(i)) from i=0 to n-1.

Bearbeiten: Nach einem Kommentar von Hristo Iliev wurde mir klar, dass ich akumulative / Präfixsumme.

Dies kann in Code als geschrieben werden

float sum = 0;
for(int i=0; i<N; i++) {
    sum += f(i);
    a[i] = sum;
}

Jetzt möchte ich OpenMP verwenden, um dies parallel zu tun. Eine Möglichkeit, dies mit OpenMP zu tun, besteht darin, die Werte für zu schreibenf(i) parallel und kümmern sich dann um die Abhängigkeit in Serie. Obf(i) ist eine langsame Funktion, dann könnte dies gut funktionieren, da die nicht-parallele Schleife einfach ist.

#pragma omp parallel for
for(int i=0; i<N; i++) {
    a[i] = f(i);
}
for(int i=1; i<N; i++) {
    a[i] += a[i-1];
}

Dies ist jedoch ohne die nicht parallele Schleife mit OpenMP möglich. Die Lösung, die ich mir ausgedacht habe, ist jedoch kompliziert und vielleicht hackisch. Meine Frage ist also, ob es einen einfacheren, weniger komplizierten Weg gibt, dies mit OpenMP zu tun.

Der folgende Code führt im Grunde den ersten Code aus, den ich für jeden Thread aufgelistet habe. Das Ergebnis sind die Werte vona in einem gegebenen Thread sind bis zu einer Konstanten korrekt. Ich speichere die Summe für jeden Thread in einem Arraysuma mitnthreads+1 Elemente. Auf diese Weise kann ich zwischen Threads kommunizieren und den konstanten Versatz für jeden Thread bestimmen. Dann korrigiere ich die Werte vona[i] mit dem Offset.

float *suma;
#pragma omp parallel
{
    const int ithread = omp_get_thread_num();
    const int nthreads = omp_get_num_threads();
    const int start = ithread*N/nthreads;
    const int finish = (ithread+1)*N/nthreads;
    #pragma omp single
    {
        suma = new float[nthreads+1];
        suma[0] = 0;
    }
    float sum = 0;
    for (int i=start; i<finish; i++) {
        sum += f(i);
        a[i] = sum;
    }
    suma[ithread+1] = sum;
    #pragma omp barrier
    float offset = 0;
    for(int i=0; i<(ithread+1); i++) {
        offset += suma[i];
    }
    for(int i=start; i<finish; i++) {
        a[i] += offset;
    }
}
delete[] suma;

Ein einfacher Test ist nur zu setzenf(i) = i. Dann ist die Lösunga[i] = i*(i+1)/2 (Und im Unendlichen ist es-1/12).

Antworten auf die Frage(1)

Ihre Antwort auf die Frage