Szukaj…


Uwagi

Powszechną pułapką jest przekonanie, że wszystkie wątki regionu równoległego powinny tworzyć wystąpienia (tworzyć) zadania, ale zazwyczaj tak nie jest, chyba że chcesz utworzyć tyle zadań, ile liczba wątków razy liczba elementów do przetworzenia. Dlatego w kodach zadań OpenMP znajdziesz coś podobnego do

#pragma omp parallel
#pragma omp single
...
   #pragma omp task
   { code for a given task; }
...

Równoległe przetwarzanie kontenera listy c ++ przy użyciu zadań OpenMP

#include <omp.h>
#include <unistd.h>
#include <iostream>
#include <list>

static void processElement (unsigned n)
{
    // Tell who am I. The #pragma omp critical ensures that
    // only one thread sends data to std::cout
    #pragma omp critical
    std::cout <<
      "Thread " << omp_get_thread_num() << " processing element " << n
      << std::endl;

    // Simulate some work
    usleep (n*1000);
}

int main (void)
{
    std::list<unsigned> lst;

    // Fill the list
    for (unsigned u = 0; u < 16; ++u)
            lst.push_back (1+u);

    // Now process each element of the list in parallel

    #pragma omp parallel  // Create a parallel region
    #pragma omp single    // Only one thread will instantiate tasks
    {
            for (auto element : lst)
            {
                    #pragma omp task firstprivate (element)
                    processElement (element);
            }

            // Wait for all tasks to be finished
            #pragma omp taskwait
    }

    return 0;
}

Ten przykład symuluje przetwarzanie listy STL (o nazwie lst w kodzie) równolegle poprzez konstrukcje zadań OpenMP (przy użyciu dyrektywy #pragma omp task ). W przykładzie utworzono / utworzono instancję jednego zadania OpenMP dla każdego elementu w lst a wątki OpenMP wykonują zadania, gdy tylko będą gotowe do uruchomienia.

$ OMP_NUM_THREADS=4 ./a.out
Thread 0 processing element 16
Thread 3 processing element 3
Thread 2 processing element 1
Thread 1 processing element 2
Thread 2 processing element 4
Thread 1 processing element 5
Thread 3 processing element 6
Thread 2 processing element 7
Thread 1 processing element 8
Thread 3 processing element 9
Thread 2 processing element 10
Thread 1 processing element 11
Thread 0 processing element 15
Thread 3 processing element 12
Thread 2 processing element 13
Thread 1 processing element 14

Obliczenia rekurencyjne dla pi przy użyciu zadań OpenMP

Poniższy kod oblicza wartość PI przy użyciu metody rekurencyjnej. Zmodyfikuj wartość MAX_PARALLEL_RECURSIVE_LEVEL aby określić, przy jakiej głębokości rekurencji przestań tworzyć zadania. Dzięki takiemu podejściu do tworzenia równoległości z aplikacji rekurencyjnych: im więcej zadań utworzysz, tym więcej utworzonych zadań równoległych, ale także mniej pracy na zadanie. Dlatego wygodnie jest eksperymentować z aplikacją, aby zrozumieć, na jakim poziomie tworzenie kolejnych zadań nie przynosi korzyści pod względem wydajności.

#include <stdio.h>
#include <omp.h>

double pi_r (double h, unsigned depth, unsigned maxdepth, unsigned long long begin, unsigned long long niters)
{
    if (depth < maxdepth)
    {
        double area1, area2;

        // Process first half
        #pragma omp task shared(area1)
        area1 = pi_r (h, depth+1, maxdepth, begin, niters/2-1);

        // Process second half
        #pragma omp task shared(area2)
        area2 = pi_r (h, depth+1, maxdepth, begin+niters/2, niters/2);

        #pragma omp taskwait

        return area1+area2;
    }
    else
    {

        unsigned long long i;
        double area = 0.0;

        for (i = begin; i <= begin+niters; i++)
        {
            double x = h * (i - 0.5);
            area += (4.0 / (1.0 + x*x));
        }

        return area;
    }
}

double pi (unsigned long long niters)
{
    double res;
    double h = 1.0 / (double) niters;

    #pragma omp parallel shared(res)
    {
#define MAX_PARALLEL_RECURSIVE_LEVEL 4

        #pragma omp single
        res = pi_r (h, 0, MAX_PARALLEL_RECURSIVE_LEVEL, 1, niters);
    }
    return res * h;
}


int main (int argc, char *argv[])
{
#define NITERS (100*1000*1000ULL)

    printf ("PI (w/%d iters) is %lf\n", NITERS, pi(NITERS));

    return 0;
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow