过去几天我一直在努力解决一个奇怪的问题.我们使用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)用过的).
有任何想法吗?在谷歌上没有找到任何东西 - 或者我使用了错误的关键字:)
OpenMP是代码与其执行之间的中介.每个#pragma omp
语句都转换为对其根据OpenMP库函数的调用,并且它就是它的全部内容.多线程执行(启动线程,加入和同步它们等)始终由操作系统(OS)处理.所有OpenMP都会在一个简短而甜蜜的界面中为我们处理这些低级别依赖于操作系统的线程调用.
该-fopenmp
标志是一个高级别的标志,它不仅包括GCC的OpenMP实现(gomp).这个gomp库需要更多的库来访问操作系统的线程功能.在符合POSIX的操作系统上,OpenMP通常基于pthread,需要链接.它可能还需要实时扩展库(librt)来处理某些操作系统,而不是其他操作系统.当使用动态链接,一切都应该被自动发现,但是当你指定的-static
,我觉得你在用的Jakub耶利内克所描述的情况已经爱上了这里.但是现在,pthread(和rt,如果需要)应该在-static
使用时自动链接.
除了链接依赖项之外,该-fopenmp
标志还会激活一些pragma语句处理.您可以在整个GCC代码中看到(如此处和此处)没有-fopenmp
标志(仅通过链接gomp库不触发),多个pragma将不会转换为相应的OpenMP函数调用.我只是想用一些示例代码,都-lgomp
和-fopenmp
生产,对相同的库链接工作的可执行文件.我的简单示例中唯一的区别是它-fopenmp
有一个-lgomp
没有的符号:( 这里是GOMP_parallel@@GOMP_4.0+
代码),它是初始化执行我的示例代码所请求的forks的并行部分的函数.就这样#pragma omp parallel
-lgomp
版本没有将pragma转换为对GCC的OpenMP实现的调用.两者都产生了可运行的可执行文件,但-fopenmp
在这种情况下只有标志产生了并行可执行文
要结束,-fopenmp
GCC需要处理所有OpenMP pragma.没有它,您的并行部分将不会分叉任何线程,这可能会造成严重破坏,具体取决于您的内部代码所做的假设.