/openmp
(OpenMP サポートの有効化)
OpenMP をサポートした方法で #pragma omp
ディレクティブを処理するようにコンパイラに指示します。
構文
/openmp
/openmp:experimental
/openmp:llvm
/openmp
解説
#pragma omp
は、ディレクティブと句を指定するために使用されます。 コンパイルで /openmp
が指定されていない場合、コンパイラは OpenMP の句とディレクティブを無視します。 OpenMP 関数の呼び出しは、/openmp
が指定されていない場合でもコンパイラによって処理されます。
C++ コンパイラは現在、OpenMP 2.0 標準をサポートしています。 Visual Studio 2019 では、SIMD 機能も提供されるようになりました。 SIMD を使用するには、 /openmp:experimental
オプションを使用してコンパイルします。 このオプションを使用すると、通常の OpenMP 機能と、/openmp
スイッチを使用しているときには使用できない OpenMP SIMD 機能の両方が有効になります。
Visual Studio 2019 バージョン 16.9 以降では、/openmp
の代わりに試験的な /openmp:llvm
オプションを使用して、LLVM OpenMP ランタイムをターゲットにすることができます。 必要な libomp DLL が再頒布可能になっていないため、現在、運用コードについてはサポートは提供されていません。 このオプションは、/openmp
と同じ OpenMP 2.0 ディレクティブをサポートしています。 また、/openmp:experimental
オプションでサポートされている SIMD ディレクティブもすべてサポートされています。 さらに、OpenMP 3.0 標準に従って、parallel for ループでの符号なし整数インデックスもサポートされます。 詳しくは、Visual Studio での C++ に対する OpenMP サポートの強化に関する記事をご覧ください。
/openmp:llvm
オプションでは、x64 アーキテクチャがサポートされています。 Visual Studio 2019 バージョン 16.10 以降では、x86 および ARM64 アーキテクチャもサポートされています。 このオプションは、 /clr
または /ZW
と互換性がありません。
/openmp
と /clr
の両方を使用してコンパイルされたアプリケーションは、1 つのアプリケーション ドメイン プロセスでのみ実行できます。 複数のアプリケーション ドメインはサポートされていません。 つまり、モジュール コンストラクター (.cctor
) が実行されると、プロセスが /openmp
を使用してコンパイルされるのかどうかと、アプリが既定以外のランタイムに読み込まれるかどうかが検出されます。 詳しくは、「appdomain
」、「/clr
(共通言語ランタイムのコンパイル)」、および「混在アセンブリの初期化」をご覧ください。
/openmp
と /clr
の両方を使用してコンパイルされたアプリを既定以外のアプリケーション ドメインに読み込もうとすると、TypeInitializationException 例外がデバッガーの外部でスローされ、デバッガーで OpenMPWithMultipleAppdomainsException
例外がスローされます。
これらの例外は、次の状況でも発生する可能性があります。
アプリケーションが
/openmp
ではなく/clr
を使用してコンパイルされ、既定以外のアプリケーション ドメインに読み込まれた場合で、/openmp
を使用してコンパイルされたアプリがプロセスに含まれている場合。/clr
アプリをユーティリティ (regasm.exe など) に渡して、ターゲット アセンブリが既定以外のアプリケーション ドメインに読み込まれた場合。
共通言語ランタイムのコード アクセス セキュリティは、OpenMP リージョンでは機能しません。 CLR のコード アクセス セキュリティ属性を並列リージョンの外部に適用した場合、その属性は並列リージョンでは有効になりません。
部分的に信頼された呼び出し元を許可する /openmp
アプリを作成することはお勧めしません。 AllowPartiallyTrustedCallersAttribute は使用せず、CLR コード アクセス セキュリティ属性も一切使用しないでください。
Visual Studio 開発環境でこのコンパイラ オプションを設定するには
プロジェクトの [プロパティ ページ] ダイアログ ボックスを開きます。 詳細については、Visual Studio での C++ コンパイラとビルド プロパティの設定に関する記事を参照してください。
[構成プロパティ]>[C/C++]>[言語] プロパティ ページを展開します。
[OpenMP サポート] プロパティを変更します。
このコンパイラ オプションをコードから設定するには
- 以下を参照してください。OpenMP
例
次の例は、スレッド プールの起動と、起動後のスレッド プールの使用による影響の一部を示したものです。 x64、シングル コア、デュアル プロセッサを想定した場合、スレッド プールの起動には約 16 ミリ秒かかります。 その後、スレッド プールのための追加コストはほとんど発生しません。
/openmp
を使用してコンパイルする場合、test2 に対する 2 回目の呼び出しにかかる時間が、/openmp-
を使用してコンパイルする場合よりも長くなることはありません (スレッド プールの起動がないため)。 100 万回のイテレーションを行った場合は、/openmp-
バージョンよりも /openmp
バージョンのほうが、test2 の 2 回目の呼び出しが高速になります。 25 回のイテレーションでは、/openmp-
と /openmp
のどちらのバージョンについても、登録はクロック粒度未満になります。
アプリケーションにループが 1 つしかなく、15 ミリ秒未満 (コンピューターの概算オーバーヘッドに合わせて調整されます) で実行される場合、/openmp
は適さない可能性があります。 それを超える場合には、/openmp
の使用を検討してください。
// cpp_compiler_options_openmp.cpp
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
volatile DWORD dwStart;
volatile int global = 0;
double test2(int num_steps) {
int i;
global++;
double x, pi, sum = 0.0, step;
step = 1.0 / (double) num_steps;
#pragma omp parallel for reduction(+:sum) private(x)
for (i = 1; i <= num_steps; i++) {
x = (i - 0.5) * step;
sum = sum + 4.0 / (1.0 + x*x);
}
pi = step * sum;
return pi;
}
int main(int argc, char* argv[]) {
double d;
int n = 1000000;
if (argc > 1)
n = atoi(argv[1]);
dwStart = GetTickCount();
d = test2(n);
printf_s("For %d steps, pi = %.15f, %d milliseconds\n", n, d, GetTickCount() - dwStart);
dwStart = GetTickCount();
d = test2(n);
printf_s("For %d steps, pi = %.15f, %d milliseconds\n", n, d, GetTickCount() - dwStart);
}