/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 開発環境でこのコンパイラ オプションを設定するには

  1. プロジェクトの [プロパティ ページ] ダイアログ ボックスを開きます。 詳細については、Visual Studio での C++ コンパイラとビルド プロパティの設定に関する記事を参照してください。

  2. [構成プロパティ]>[C/C++]>[言語] プロパティ ページを展開します。

  3. [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);
}

関連項目

MSVC コンパイラ オプション
MSVC コンパイラのコマンド ライン構文
MSVC の OpenMP