【问题标题】:Difference between linking OpenMP with -fopenmp and -lgomp将 OpenMP 与 -fopenmp 和 -lgomp 链接的区别
【发布时间】:2014-04-08 13:16:09
【问题描述】:

过去几天我一直在努力解决一个奇怪的问题。我们使用 GCC 4.8 创建了一些库,它们静态链接了它们的一些依赖项——例如。 log4cplus 或提升。对于这些库,我们使用 boost-python 创建了 Python 绑定。

每次这样的库使用 TLS(如 log4cplus 在它的静态初始化中所做的或 stdlibc++ 在抛出异常时所做的 - 不仅在初始化阶段),整个事情都会在段错误中崩溃 - 每次线程局部变量的地址为 0。

我尝试了所有方法,例如重新编译、确保使用 -fPIC、确保使用 -tls-model=global-dynamic 等等。没有成功。然后今天我发现这些崩溃的原因是我们链接 OpenMP 的方式。我们使用“-lgomp”而不是仅仅使用“-fopenmp”来做到这一点。因为我改变了这个一切正常 - 没有崩溃,没有什么。很好!

但我真的很想知道问题的原因是什么。那么这两种在 OpenMP 中链接的可能性有什么区别呢?

我们在这里有一台 CentOS 5 机器,我们在 /opt/local/gcc48 中安装了 GCC-4.8,我们还确定来自 /opt/local/gcc48 的 libgomp 以及来自的 libstdc++ 已被使用那里(使用了 DL_DEBUG)。

有什么想法吗?在 Google 上没有找到任何东西 - 或者我使用了错误的关键字:)

【问题讨论】:

  • -pthread 或 -lpthread 已经存在
  • -v编译并比较输出...
  • 添加 -v 作为链接器选项表明 -fopenmp 在末尾隐式添加了 -lgomp。其他一切都保持不变。如果没有 -fopenp,我有“-lstdc++ -lm -lgcc_s -lpthread -lc -lgcc_s”,而使用 -fopenmp 它变成“-lstdc++ -lm -lgomp -lgcc_s -lpthread -lc -lgcc_s”。我仍然看不到崩溃的原因,因为所有这些库都是动态链接的 :(
  • 那么它可能是重要的 -l 标志的顺序。也许 -lgomp 在 -lpthread 或其他一些排列之前很重要。您可以尝试使用 LD_PRELOAD 来查看以不同的顺序加载依赖项是否会产生影响。
  • LD_PRELOADing libgomp.so 确实有效 - 所以在加载有关 TLS 的 OpenMP 时似乎发生了一些有趣的事情......让我们看看我们是否能找出那里到底发生了什么......

标签: c++ openmp static-linking dlopen


【解决方案1】:

OpenMP 是您的代码及其执行之间的中介。每个#pragma omp 语句都转换为对其相应OpenMP 库函数的调用,这就是它的全部内容。多线程执行(启动线程、加入和同步它们等)始终由操作系统 (OS) 处理。 OpenMP 所做的只是在一个简短而友好的接口中为我们处理这些依赖于操作系统的低级线程调用。

-fopenmp 标志是一个高级标志,它不仅仅包含 GCC 的 OpenMP 实现 (gomp)。这个 gomp 库将需要更多库来访问操作系统的线程功能。在 POSIX 兼容的操作系统上,OpenMP 通常基于 pthread,需要链接。它可能还需要实时扩展库 (librt) 才能在某些操作系统上工作,而在其他操作系统上则不行。使用动态链接时,应该自动发现所有内容,但是当您指定-static 时,我认为您已陷入 Jakub Jelinek here 描述的情况。但是现在,当使用-static 时,应该自动链接 pthread(如果需要,还可以链接 rt)。

除了链接依赖关系之外,-fopenmp 标志还激活了一些 pragma 语句处理。您可以在整个 GCC 代码(如 herehere)中看到,如果没有 -fopenmp 标志(仅通过链接 gomp 库不会触发),多个 pragma 将不会转换为适当的 OpenMP 函数称呼。我刚刚尝试了一些示例代码,-lgomp-fopenmp 都生成了一个链接到相同库的工作可执行文件。在我的简单示例中,唯一的区别是 -fopenmp 有一个 -lgomp 没有的符号:GOMP_parallel@@GOMP_4.0+(代码 here)这是初始化并行部分的函数,该函数执行 @ 请求的分叉987654336@ 在我的示例代码中。因此,-lgomp 版本没有将编译指示转换为对 GCC 的 OpenMP 实现的调用。两者都生成了一个工作可执行文件,但在这种情况下,只有-fopenmp 标志生成了一个并行可执行文件。

最后,GCC 需要-fopenmp 来处理所有 OpenMP 编译指示。没有它,您的并行部分将不会分叉任何线程,这可能会造成严重破坏,具体取决于您完成内部代码的假设。

【讨论】:

  • 在您的示例中,您是否使用-fopenmp 构建(编译)源代码,然后使用您的.o-fopenmp / -lgomp 链接?当您使用gcc -fopenmp example.c 时,它将在编译中启用 omp pragma 并在链接中添加库;但是gcc -lgomp example.c 形式的单个命令compile+link 不会将openmp-enabling 选项传递给编译,并且pragma omp 将被忽略。
  • 我可能错了,但我相信我们说的是同一件事?我写了“只有-fopenmp 会生成并行可执行文件”,而您写了“-lgomp 不会生成并行可执行文件”之类的内容,还是我错过了什么? (正如我所写,如果没有-fopenmp,pragma 不会转换为函数调用)无论如何,我同意你所说的,我相信答案也是一样的。不过,也许我的回答措辞会更好……
猜你喜欢
  • 2013-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-01
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 2013-12-17
相关资源
最近更新 更多