/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: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 开发环境中设置此编译器选项
打开项目的“属性页” 对话框。 有关详细信息,请参阅在 Visual Studio 中设置 C++ 编译器和生成属性。
展开“配置属性”>“C/C++”>“语言”属性页。
修改“OpenMP 支持”属性。
以编程方式设置此编译器选项
- 请参阅 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);
}