问题描述
最近几天,我一直在努力解决一个奇怪的问题.我们使用GCC 4.8创建了一些库,这些库静态链接了它们的某些依赖项-例如. log4cplus或boost.对于这些库,我们使用boost-python创建了Python绑定.
I've been struggling a weird problem the last few days. We create some libraries using GCC 4.8 which link some of their dependencies statically - eg. log4cplus or boost. For these libraries we have created Python bindings using boost-python.
每次这样的库使用TLS(就像log4cplus进行静态初始化时一样,或者stdlibc ++在引发异常时(不仅在初始化阶段时)那样),整个事件都在segfault中崩溃-以及每次线程局部变量的地址已经为0.
Every time such a library used TLS (like log4cplus does in it's static initialization or stdlibc++ does when throwing an exception - not only during initialization phase) the whole thing crashed in a segfault - and every time the address of the thread local variable has been 0.
我尝试了所有操作,例如重新编译,确保使用-fPIC,确保使用-tls-model = global-dynamic等.没有成功.然后,今天我发现这些崩溃的原因是我们链接OpenMP的方式.我们使用"-lgomp"而不是仅使用"-fopenmp"来完成此操作.由于我更改了此设置,所以一切正常-没有崩溃,也没有任何问题.很好!
I tried everything like recompiling, ensuring -fPIC is used, ensuring -tls-model=global-dynamic is used, etc. No success. Then today I found out that the reason for these crashes has been our way of linking OpenMP in. We did this using "-lgomp" instead of just using "-fopenmp". Since I changed this everything works fine - no crashes, no nothing. Fine!
但是我真的很想知道问题的原因是什么.那么在OpenMP中链接这两种可能性之间有什么区别?
But I'd really like to know what the cause of the problem was. So what's the difference between these two possibilities to link in OpenMP?
我们这里有一台CentOS 5机器,我们在/opt/local/gcc48中安装了GCC-4.8,并且我们还确定已经使用了来自/opt/local/gcc48的libgomp以及来自的libstdc ++.在那里(使用了DL_DEBUG).
We have a CentOS 5 machine here where we have installed a GCC-4.8 in /opt/local/gcc48 and we are also sure that the libgomp coming from /opt/local/gcc48 had been used as well as the libstdc++ from there (DL_DEBUG used).
有什么想法吗?在Google上找不到任何内容-或我使用了错误的关键字:)
Any ideas? Haven't found anything on Google - or I used the wrong keywords :)
推荐答案
OpenMP是代码与其执行之间的中介.每个#pragma omp
语句都转换为对它们相应的OpenMP库函数的调用,并且所有这些都已存在.多线程执行(启动线程,加入和同步线程等)始终由操作系统(OS)处理. OpenMP所做的全部工作就是在一个简短而优美的界面中轻松地为我们处理这些与底层操作系统相关的线程调用.
OpenMP is an intermediary between your code and its execution. Each #pragma omp
statement are converted to calls to their according OpenMP library function, and it's all there is to it. The multithreaded execution (launching threads, joining and synchronizing them, etc.) is always handled by the Operating System (OS). All OpenMP does is handling these low-level OS-dependent threading calls for us portably in a short and sweet interface.
-fopenmp
标志是一个高级标志,其作用不仅仅包括GCC的OpenMP实现(gomp).这个gomp库将需要更多的库来访问操作系统的线程功能.在符合POSIX的操作系统上,OpenMP通常基于pthread,需要将其链接.它可能还需要实时扩展库(librt)在某些OS上运行,而在其他OS上则不需要.使用动态链接时,应该自动发现所有内容,但是当您指定-static
时,我认为您已经陷入了Jakub Jelinek 此处.但是如今,使用-static
时应该自动链接pthread(如果需要,还可以带rt).
The -fopenmp
flag is a high-level one that does more than include GCC's OpenMP implementation (gomp). This gomp library will require more libraries to access the threading functionality of the OS. On POSIX-compliant OSes, OpenMP is usually based on pthread, which needs to be linked. It may also need the realtime extension library (librt) to work on some OSes, while not on some other. When using dynamic linking, everything should be discovered automatically, but when you specified -static
, I think you've fallen in the situation described by Jakub Jelinek here. But nowadays, pthread (and rt if needed) should be automatically linked when -static
is used.
除了链接依赖项之外,-fopenmp
标志还激活一些编译指示语句处理.您可以在整个GCC代码中看到(如此处和此处)没有-fopenmp
标志(仅通过链接gomp库不会触发),多个编译指示将不会转换为适当的OpenMP函数调用.我只是尝试了一些示例代码,并且-lgomp
和-fopenmp
都生成了可工作的可执行文件,该可执行文件链接到相同的库.在我的简单示例中,唯一的区别是-fopenmp
具有-lgomp
不具有的符号:GOMP_parallel@@GOMP_4.0+
(代码此处)是用于初始化并行段的函数,该并行段执行示例代码中#pragma omp parallel
所请求的派生.因此,-lgomp
版本没有将编译指示转换为对GCC的OpenMP实现的调用.两者都生成了一个可运行的可执行文件,但是在这种情况下,只有-fopenmp
标志生成了一个并行可执行文件.
Aside from linking dependencies, the -fopenmp
flag also activates some pragma statement processing. You can see throughout the GCC code (as here and here) that without the -fopenmp
flag (which isn't trigged by only linking the gomp library), multiple pragmas won't be converted to the appropriate OpenMP function call. I just tried with some example code, and both -lgomp
and -fopenmp
produce a working executable that links against the same libraries. The only difference in my simple example that the -fopenmp
has a symbol that the -lgomp
doesn't have: GOMP_parallel@@GOMP_4.0+
(code here) which is the function that initializes the parallel section performing the forks requested by the #pragma omp parallel
in my example code. Thus, the -lgomp
version did not translate the pragma to a call to GCC's OpenMP implementation. Both produced a working executable, but only the -fopenmp
flag produced a parallel executable in this case.
最后,GCC需要-fopenmp
来处理所有OpenMP编译指示.如果没有它,您的并行部分将不会派生任何线程,这可能会给内部线程造成严重破坏,具体取决于您执行内部代码的假设.
To wrap up, -fopenmp
is needed for GCC to process all the OpenMP pragmas. Without it, your parallel sections won't fork any thread, which could wreak havoc depending on the assumptions on which your inner code was done.
这篇关于将OpenMP与-fopenmp和-lgomp链接之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!