Aze*_*gor 17 c++ multithreading shared-libraries dynamic-linking c++11
我目前正在尝试在一个共享库中使用C++ 11多线程,该库被加载到Linux上的主程序(用C语言编写)中.这是大型模拟程序的一部分,我无法改变有关库加载或更改主程序的任何内容.
主程序是用gcc 4.1.2编译的,我没有它的源代码(我不能用gcc 4.8.2重新编译它).
共享库使用gcc 4.8.2编译,以便使用C++ 11多线程.我正在传递编译器命令
-pthread -lpthread -std=c++11
Run Code Online (Sandbox Code Playgroud)
正如在Linux下的GCC中使用std :: thread的正确链接选项中所解释的那样?
使用此配置(" -pthread -std=c++11"和gcc 4.8)编译独立测试程序在我的系统上正常工作.但是当我启动加载共享库的程序时,我得到一个异常:
Caught std::exception!
Exception Message: Enable multithreading to use std::thread: Operation not permitted
Terminating...
Run Code Online (Sandbox Code Playgroud)
使用-pthread和-lpthread(编辑:也只是-pthread没有-lpthread)编译参数不起作用.编译器参数是(我正在使用cook构建系统):
-pthread -std=c++11 -fmessage-length=0 -fPIC -Wchar-subscripts ...(lots of -W* here)
... -Wunused-variable -m64 -D__64BIT__ -pthread -lpthread
Run Code Online (Sandbox Code Playgroud)
和链接器参数(由于构建系统而产生的重复参数):
-pthread -lpthread -std=c++11 -pthread -lpthread -std=c++11 -shared -fPIC -Wl,-Bsymbolic -Wl,--allow-shlib-undefined -pthread -lpthread
Run Code Online (Sandbox Code Playgroud)
在我的库上调用ldd会给出以下输出
$ ldd calc3/build/amd64_linux26_RH5/library.so
linux-vdso.so.1 => (0x00007fff4d1fd000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00002ae6ec124000)
libstdc++.so.6 => /afs/bb/data/d6833/util/gcc_482/lib64/libstdc++.so.6 (0x00002ae6ec340000)
libm.so.6 => /lib64/libm.so.6 (0x00002ae6ec655000)
libgcc_s.so.1 => /afs/bb/data/d6833/util/gcc_482/lib64/libgcc_s.so.1 (0x00002ae6ec8d8000)
libc.so.6 => /lib64/libc.so.6 (0x00002ae6ecaef000)
/lib64/ld-linux-x86-64.so.2 (0x00000032cb400000)
Run Code Online (Sandbox Code Playgroud)
并在主程序上
$ ldd .../bin-64/main_program
linux-vdso.so.1 => (0x00007fff64595000)
libdl.so.2 => /lib64/libdl.so.2 (0x00000032cc000000)
libz.so.1 => /usr/lib64/libz.so.1 (0x00000032cc800000)
libc.so.6 => /lib64/libc.so.6 (0x00000032cb800000)
/lib64/ld-linux-x86-64.so.2 (0x00000032cb400000)
Run Code Online (Sandbox Code Playgroud)
pthread库链接到我的共享库,但不链接到主程序.这个答案表明你必须将pthreads链接到主程序,但是这个答案的第二个评论(由@R ..)表示没有必要(这听起来像逻辑上).
不幸的是,除了我的库使用另一个C++库作为API之外,我对整个系统的加载机制一无所知.
请注意,其他C++ 11功能可以工作(和libstdc ++.所以在我的库的依赖项中),但C++ 11多线程不是(尽管libpthread.so也在我的库的依赖项中).
使用程序本身包含的库中的线程类是可行的(这个线程类似乎也使用pthreads).
我也试过使用-fabi-version=0或-fabi-version=2因为主程序是用我的库用gcc 4.1.2编译的,但它没有改变任何东西.
有什么我忽略的或者我可以使用编译器选项来使它工作吗?或者它似乎是我的程序环境的问题?欢迎任何想法.
编辑:
我尝试使用-Wl,-no-as-needed(如评论中所建议的那样),但遗憾的是它没有改变任何东西.
使用clang 3.5而不是gcc 4.8也不起作用.
只要我对主应用程序和共享库使用gcc 4.8或clang 3.5,创建一个加载共享库的小型测试应用程序(如下面@chill的答案)就可以工作(即使没有编译器标志).当使用gcc 4.1作为主程序时,主程序甚至无法加载库(它在我的'真实'应用程序中工作).我认为编译器的不同ABI可能存在问题.
直接使用pthreads pthread.h似乎工作(虽然程序目前终止pthread_join没有错误消息,但我仍然在那里测试...)
编辑2:
运行'测试程序' LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH(因为gcc 4.8库路径也需要在那里,感谢@MvG)确实运行程序但是再次崩溃,但Enable multithreading to use std::thread: Operation not permitted异常.
我检查了所有其他加载的库(找到strace ./main_program 2>&1 | grep '^open(".*\.so"' [见这里 ])并用它们全部检查ldd.它们都依赖于相同的库(具有相同的路径).ldd输出(在所有这些上):
linux-vdso.so.1 => (0x00007fff4d3fd000)
libstdc++.so.6 => /afs/bb/data/d6833/util/gcc_482/lib64/libstdc++.so.6 (0x00002ade28774000)
libm.so.6 => /lib64/libm.so.6 (0x00002ade28ab0000)
libgcc_s.so.1 => /afs/bb/data/d6833/util/gcc_482/lib64/libgcc_s.so.1 (0x00002ade28d33000)
libc.so.6 => /lib64/libc.so.6 (0x00002ade28f49000)
/lib64/ld-linux-x86-64.so.2 (0x00000032ea200000)
Run Code Online (Sandbox Code Playgroud)
(他们都不依赖于libpthread.so.0,除了我的库和另外一个(但它是相同的/lib64/libpthread.so.0))
有些库确实有更多的依赖项(它们似乎与线程无关)但似乎没有任何"冲突"依赖项(在这些库中没有依赖于同一个库的不同版本/路径).
MvG*_*MvG 12
在thread.cc你可以阅读这个例外是如果产生__gthread_active_p返回false.该调用只是检查给定符号是否可用.有问题的符号是一个弱符号:它不必存在,但检查它的存在以决定是否支持线程.
但是符号的存在意味着什么?在这种情况下,它表示符号位于符号表列表中,相关库(libgcc_s.so.1在我的示例中)搜索符号定义.这包括应用程序本身导出的符号,以及由之前加载的所有库导出的符号.但是,它不包括之后加载的库.不幸的是,如果之前libgcc加载了,那么该符号在其搜索域中不可用.因此它报告线程不受支持.我猜你在多线程之前加载了一些其他的C++模块,所以你遇到了这个问题. libpthread
在我的再现示例中工作的一种解决方案是LD_PRELOAD=/lib64/libpthread.so.0在用于调用二进制文件的环境中进行设置.它libpthread在前面加载,因此它的符号可用于满足弱符号链接.这对setuid/setgid二进制文件不起作用,在其他情况下也可能被认为是丑陋的黑客,所以我对更清晰的解决方案感兴趣.然而,这大部分时间都可以完成工作.
| 归档时间: |
|
| 查看次数: |
4133 次 |
| 最近记录: |