方法: OpenMP の parallel for ループを変換し、コンカレンシー ランタイムを使用する
この例では、OpenMP の parallel ディレクティブと for ディレクティブを使用する基本的なループを変換して、同時実行ランタイムの concurrency::parallel_for アルゴリズムを使用する方法を示します。
例 - 素数の数
この例では、OpenMP とコンカレンシー ランタイムの両方を使用して、ランダム値の配列に含まれる素数の数を計算します。
// concrt-omp-count-primes.cpp
// compile with: /EHsc /openmp
#include <ppl.h>
#include <random>
#include <array>
#include <iostream>
using namespace concurrency;
using namespace std;
// Determines whether the input value is prime.
bool is_prime(int n)
{
if (n < 2)
return false;
for (int i = 2; i < n; ++i)
{
if ((n % i) == 0)
return false;
}
return true;
}
// Uses OpenMP to compute the count of prime numbers in an array.
void omp_count_primes(int* a, size_t size)
{
if (size == 0)
return;
size_t count = 0;
#pragma omp parallel for
for (int i = 0; i < static_cast<int>(size); ++i)
{
if (is_prime(a[i])) {
#pragma omp atomic
++count;
}
}
wcout << L"found " << count
<< L" prime numbers." << endl;
}
// Uses the Concurrency Runtime to compute the count of prime numbers in an array.
void concrt_count_primes(int* a, size_t size)
{
if (size == 0)
return;
combinable<size_t> counts;
parallel_for<size_t>(0, size, [&](size_t i)
{
if (is_prime(a[i])) {
counts.local()++;
}
});
wcout << L"found " << counts.combine(plus<size_t>())
<< L" prime numbers." << endl;
}
int wmain()
{
// The length of the array.
const size_t size = 1000000;
// Create an array and initialize it with random values.
int* a = new int[size];
mt19937 gen(42);
for (size_t i = 0; i < size; ++i) {
a[i] = gen();
}
// Count prime numbers by using OpenMP and the Concurrency Runtime.
wcout << L"Using OpenMP..." << endl;
omp_count_primes(a, size);
wcout << L"Using the Concurrency Runtime..." << endl;
concrt_count_primes(a, size);
delete[] a;
}
この例を実行すると、次の出力が生成されます。
Using OpenMP...
found 107254 prime numbers.
Using the Concurrency Runtime...
found 107254 prime numbers.
parallel_for
アルゴリズムおよび OpenMP 3.0 では、インデックス型を符号付き整数型として使用することも、符号なし整数型として使用することもできます。 また、parallel_for
アルゴリズムを使用すると、指定の範囲が符号付きの型をオーバーフローすることがなくなります。 OpenMP Version 2.0 および 2.5 では、符号付き整数のインデックス型しか使用できません。 また、OpenMP でインデックス範囲は検証されません。
この例の同時実行ランタイムを使用するバージョンでは、atomic ディレクティブの代わりに concurrency::combinable オブジェクトを使用して、同期を必要とせずにカウンター値をインクリメントします。
parallel_for
および他の並列アルゴリズムの詳細については、「並列アルゴリズム」を参照してください。 combinable
クラスの詳細については、「並列コンテナーと並列オブジェクト」を参照してください。
例 - std::array の使用
この例では、ネイティブ配列ではなく、std::array オブジェクトに作用するように前の例を変更しています。 OpenMP バージョン 2.0 および 2.5 では、parallel_for
コンストラクトで符号付き整数のインデックス型しか使用できないため、反復子を使用して C++ 標準ライブラリ コンテナーの要素に並列にアクセスすることはできません。 並列パターン ライブラリ (PPL) には、反復コンテナー (C++ 標準ライブラリで提供されるものなど) でタスクを並列に実行する、concurrency::parallel_for_each アルゴリズムが用意されています。 このアルゴリズムでは、parallel_for
アルゴリズムで使用されるのと同じ分割ロジックが使用されます。 parallel_for_each
アルゴリズムは C++ 標準ライブラリの std::for_each アルゴリズムと似ていますが、parallel_for_each
アルゴリズムではタスクを同時に実行する点が異なります。
// Uses OpenMP to compute the count of prime numbers in an
// array object.
template<size_t Size>
void omp_count_primes(const array<int, Size>& a)
{
if (a.size() == 0)
return;
size_t count = 0;
int size = static_cast<int>(a.size());
#pragma omp parallel for
for (int i = 0; i < size; ++i)
{
if (is_prime(a[i])) {
#pragma omp atomic
++count;
}
}
wcout << L"found " << count
<< L" prime numbers." << endl;
}
// Uses the Concurrency Runtime to compute the count of prime numbers in an
// array object.
template<size_t Size>
void concrt_count_primes(const array<int, Size>& a)
{
if (a.size() == 0)
return;
combinable<size_t> counts;
parallel_for_each(begin(a), end(a), [&counts](int n)
{
if (is_prime(n)) {
counts.local()++;
}
});
wcout << L"found " << counts.combine(plus<size_t>())
<< L" prime numbers." << endl;
}
コードのコンパイル
コード例をコピーし、Visual Studio プロジェクトに貼り付けるか、concrt-omp-count-primes.cpp
という名前のファイルに貼り付けてから、Visual Studio のコマンド プロンプト ウィンドウで次のコマンドを実行します。
cl.exe /EHsc /openmp concrt-omp-count-primes.cpp