Поиск…


замечания

Общим явлением является то, что все потоки параллельного региона должны создавать экземпляры (создавать) задачи, но это обычно не так, если вы не хотите создавать столько задач, сколько количество потоков умножает число обрабатываемых элементов. Поэтому в кодах задач OpenMP вы найдете нечто похожее на

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

Параллельная обработка контейнера списка c ++ с использованием задач 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;
}

Этот пример имитирует обработку списка STL (называемого lst в коде) параллельно через конструкцию задачи OpenMP (с помощью директивы #pragma omp task ). В примере создается / создает одну задачу OpenMP для каждого элемента в lst а потоки OpenMP выполняют задачи, как только они будут готовы к запуску.

$ 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

Рекурсивный расчет для pi с использованием задач OpenMP

В приведенном ниже коде вычисляется значение PI с использованием рекурсивного подхода. Измените значение MAX_PARALLEL_RECURSIVE_LEVEL чтобы определить, при какой глубине рекурсии перестают создавать задачи. При таком подходе к созданию параллелизма из рекурсивных приложений: чем больше задач вы создаете, тем больше создаваемых параллельных задач, а также меньшей работы для каждой задачи. Поэтому удобно экспериментировать с приложением, чтобы понять, на каком уровне он создает дополнительные задачи, не выгодно с точки зрения производительности.

#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
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow