サーチ…


備考

一般的な落とし穴は、並列領域のすべてのスレッドがタスクをインスタンス化(作成)する必要があると信じることですが、処理する要素の数にスレッド数を掛けた数だけのタスクを作成しない限り、通常はそうではありません。したがって、OpenMPのタスクコードでは、

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

OpenMPタスクを使用したC ++リストコンテナの並列処理

#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;
}

この例では、( #pragma omp taskディレクティブを使用して)OpenMPタスク構造を介して並列にSTLリスト(コード内でlst )の処理をシミュレートします。この例では、 lst各要素に対して1つのOpenMPタスクを作成またはインスタンス化し、実行準備が整うとすぐに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

OpenMPタスクを使ったpiの再帰的計算

以下のコードは、再帰的アプローチを使用して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