/openmp(启用 OpenMP 支持)

使编译器处理支持 OpenMP 的 #pragma omp 指令。

语法

/openmp
/openmp:experimental
/openmp:llvm

/openmp

备注

#pragma omp 用于指定指令子句。 如果未在编译中指定 /openmp,编译器会忽略 OpenMP 子句和指令。 即使未指定 /openmpOpenMP 函数调用也由编译器处理。

C++ 编译器当前支持 OpenMP 2.0 标准。 现在,Visual Studio 2019 还提供 SIMD 功能。 要使用 SIMD,请使用 /openmp:experimental 选项进行编译。 此选项同时启用常规 OpenMP 功能和使用 /openmp 开关时不可用的 OpenMP SIMD 功能。

从 Visual Studio 2019 版本 16.9 开始,可以使用实验性的 /openmp:llvm 选项,而不使用面向 LLVM OpenMP 运行时的 /openmp。 目前不支持生产代码,因为所需的 libomp DLL 不可再发行。 该选项支持与 /openmp 相同的 OpenMP 2.0 指令。 并且,它支持 /openmp:experimental 选项支持的所有 SIMD 指令。 它还支持并行 for 循环中符合 OpenMP 3.0 标准版要求的无符号整数索引。 有关详细信息,请参阅 Visual Studio 中改进的对 C++ 的 OpenMP 支持

此选项 /openmp:llvm 支持 x64 体系结构。 从 Visual Studio 2019 版本 16.10 开始,它还支持 x86 和 ARM64 体系结构。 此选项与 /clr/ZW 不兼容。

使用 /openmp/clr 编译的应用程序只能在单个应用程序域进程中运行。 不支持多个应用程序域。 也就是说,当模块构造函数 (.cctor) 运行时,它会检测进程是否是使用 /openmp 编译的,以及应用是否加载到非默认运行时中。 有关详细信息,请参阅appdomain/clr(公共语言运行时编译)混合程序集的初始化

如果尝试将使用 /openmp/clr 编译的应用加载到非默认应用程序域中,则会在调试程序外部引发 TypeInitializationException 异常,在调试程序内部引发 OpenMPWithMultipleAppdomainsException 异常。

这些异常还可能在以下情况下引发:

  • 应用程序是使用 /clr 而非 /openmp 编译的,并且加载到非默认应用程序域,其中的进程包括使用 /openmp 编译的应用。

  • 如果将 /clr 应用传递给实用工具(例如 regasm.exe),则后者会将目标程序集加载到非默认应用程序域中。

公共语言运行时的代码访问安全性在 OpenMP 区域中不起作用。 如果在并行区域外部应用 CLR 代码访问安全属性,则它不会在并行区域中生效。

Microsoft 不建议编写那些允许部分信任的调用方的 /openmp 应用。 请勿使用 AllowPartiallyTrustedCallersAttribute 或任何 CLR 代码访问安全属性。

在 Visual Studio 开发环境中设置此编译器选项

  1. 打开项目的“属性页” 对话框。 有关详细信息,请参阅在 Visual Studio 中设置 C++ 编译器和生成属性

  2. 展开“配置属性”>“C/C++”>“语言”属性页

  3. 修改“OpenMP 支持”属性。

以编程方式设置此编译器选项

示例

以下示例显示了线程池启动的一些影响,以及在启动线程池后使用线程池的一些影响。 假设使用 x64,单核,双处理器,线程池需要大约 16 毫秒才能启动。 之后,线程池几乎没有额外的成本。

使用 /openmp 进行编译时,对 test2 的第二次调用的运行时间永远不会超过使用 /openmp- 进行编译的时间,因为没有线程池启动。 进行一百万次迭代时,就对 test2 的第二次调用而言,版本 /openmp 比版本 /openmp- 更快。 进行 25 次迭代时,版本 /openmp-/openmp 注册的粒度都小于时钟粒度。

如果应用程序中只有一个循环,该循环在不到 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