结合 OpenMP、Intel MKL 和 MSVC 编译器时出现巨大内存泄漏

Huge memory leak when combining OpenMP, Intel MKL and MSVC compiler

我正在从事一个非常重视性能的相当大的 C++ 项目。因此,它依赖于英特尔 MKL 库和 OpenMP。我最近观察到相当大的内存泄漏,我可以将其缩小到以下最小示例:

#include <atomic>
#include <iostream>
#include <thread>

class Foo {
public:
  Foo() : calculate(false) {}

  // Start the thread
  void start() {
    if (calculate) return;
    calculate = true;
    thread = std::thread(&Foo::loop, this);
  }

  // Stop the thread
  void stop() {
    if (!calculate) return;

    calculate = false;
    if (thread.joinable())
      thread.join();
  }

private:
  // function containing the loop that is continually executed
  void loop() {
    while (calculate) {
      #pragma omp parallel
      {
      }
    }
  }

  std::atomic<bool> calculate;
  std::thread thread;
};


int main() {
  Foo foo;
  foo.start();
  foo.stop();
  foo.start();

  // Let the program run until the user inputs something
  int a;
  std::cin >> a;

  foo.stop();
  return 0;
}

使用 Visual Studio 2013 编译并执行时,此代码每秒泄漏高达 200 MB 内存 (!)。

通过稍微修改上面的代码,泄漏就完全消失了。例如:

我是不是做错了什么,还是遗漏了什么?

MKL 的并行(默认)驱动程序是针对 Intel 的 OpenMP 运行时构建的。 MSVC 根据自己的运行时编译 OpenMP 应用程序,该运行时围绕 Win32 线程池 API 构建。两者很可能都玩得不好。只有将并行 MKL 驱动程序与使用 Intel C/C++/Fortran 编译器构建的 OpenMP 代码一起使用才是安全的。

如果你link你的OpenMP代码带有MKL的串口驱动应该没问题。这样,您可以同时从多个线程调用 MKL 并获得 MKL 的并发串行实例。 n 并发串行 MKL 调用是否比 n 线程上的单线程 MKL 调用慢、相当或更快可能取决于类型计算和硬件。

请注意,Microsoft 不再支持他们自己的 OpenMP 运行时。 MSVC 的 OpenMP 支持停留在 2.0 版,比当前规范早十多年。运行时可能存在错误(在编译器的 OpenMP 支持本身中有 bugs)并且这些错误不太可能得到修复。他们不希望您使用 OpenMP,而是希望您更喜欢他们自己的并行模式库。但是 PPL 不可移植到其他平台(例如 Linux),因此您真的应该使用 Intel Treading Building Blocks (TBB)。如果您想要 Windows 下的高质量 OpenMP 支持,请使用 Intel 编译器或某些 GCC 端口。 (我不为英特尔工作)