在动态库加载的函数中使用OpenMP时出现棘手的错误

Tho*_*asI 9 c++ compilation g++ openmp dynamic-library

我的问题涉及在动态库中存储的C++函数中使用OpenMP.让我们考虑以下代码(在shared.cpp中):

#include "omp.h"
#include <iostream>
extern "C" {
int test() { 
  int N = omp_get_max_threads();
#pragma omp parallel num_threads(N)
  {
    std::cout << omp_get_thread_num() << std::endl;
  }
  return 0;
}
};
Run Code Online (Sandbox Code Playgroud)

我使用g ++编译此代码:g ++ -fopenmp -shared -fPIC -o shared.so shared.cpp.然后,要使用测试功能,我有以下程序(main.cpp):

#include <iostream>
#include <dlfcn.h>
int main() {
  void* handle = dlopen("./shared.so", RTLD_NOW);
  if (!handle) {
    std::cerr << "can not open shared.so" << std::endl;
    return 1;
  }
  int(*f)() =  (int(*)()) dlsym(handle,"test");
  if (!f) {
    std::cerr << "can not find 'test' symbol in shared.so" << std::endl;
    return 1;
  }
  (*f)();
  if (dlclose(handle)) {
    std::cerr << "can not close shared.so" << std::endl;
    return 1;
  }  
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用以下命令编译:g ++ -o main main.cpp -ldl 问题是在程序执行的最后发生了分段错误.根据valgrind的说法,此时一些线程仍处于活动状态,这似乎与OpenMP行为一致.

这篇文章的一个解决方案(对于C代码)是使用gcc -fopenmp标志编译程序,但g ++似乎足够聪明,可以检测到该程序中从不使用OpenMP,并且从不加载OpenMP环境(汇编代码两个版本都相同).我发现的唯一解决方法是在程序中对OpenMP进行无用的调用,这迫使g ++加载OpenMP环境,然后执行正确.但对我来说,这种解决方法非常难看.我试过g ++ - 4.8.2,g ++ - 4.8.1,g ++ - 4.7.3和g ++ - 4.6.4.(使用icc-14,在程序上使用-openmp选项实际上可以解决问题).

有没有人遇到过这个问题?有更清洁的解决方法吗?谢谢,托马斯

编辑 尝试用G ++ - 4.9.2:仍然失败

wpo*_*y86 1

我认为您遇到了 libgomp(GCC 的 OpenMP 运行时库)的问题。尝试链接它:g++ -o main main.cpp -ldl -lgomp,你的段错误就会消失。

libgomp 具有一些在第一次 OpenMP 调用时初始化的内部状态。由于某种原因,如果动态加载 OpenMP 库,则不会发生取消初始化。对我来说这听起来像是一个错误。

intel 编译器有自己的 OpenMP 运行时 (libiomp5),不存在此问题。