Yue*_*oum 24 c++ gcc boost pthreads c++11
#include <iostream>
#include <map>
#include <thread>
#define SIZE 1024
#define AMOUNT 100000
#define THREADS 4
class A
{
private:
char a[SIZE];
};
void test()
{
std::cout << "test start\n";
std::map<int, A*> container;
for(int i=0; i<AMOUNT; i++)
{
A* a = new A();
std::pair<int, A*>p = std::make_pair(i, a);
container.insert(p);
}
std::cout << "test release\n";
for(int i=0; i<AMOUNT; i++)
{
auto iter = container.find(i);
delete iter->second;
container.erase(iter);
}
std::cout << "test end\n";
}
int main()
{
std::thread ts[THREADS];
for(int i=0; i<THREADS; i++)
{
ts[i] = std::thread(test);
}
for(std::thread& x: ts)
{
x.join();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面是一个简单的c ++代码.
编译: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3
ldd one,gots:
linux-vdso.so.1 => (0x00007ffebafce000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb47352a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb473313000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb4730f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb472d2a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb472a22000)
/lib64/ld-linux-x86-64.so.2 (0x00005654c5112000)
Run Code Online (Sandbox Code Playgroud)
跑./one,一切都好.
然后我尝试一个静态链接: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3 -static
ldd one,gots:
not a dynamic executable
Run Code Online (Sandbox Code Playgroud)
但是当我运行它时,有些事情出错......
test start
Segmentation fault (core dumped)
Run Code Online (Sandbox Code Playgroud)
重新编译-g,并且gdb显示:
wang[00:35][~/test]$ gdb one
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from one...done.
(gdb) run
Starting program: /home/wang/test/one
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7ffa700 (LWP 3623)]
test start
[New Thread 0x7ffff77f8700 (LWP 3624)]
test start
[New Thread 0x7ffff6ff7700 (LWP 3625)]
test start
[New Thread 0x7ffff67f6700 (LWP 3626)]
test start
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb)
Run Code Online (Sandbox Code Playgroud)
为什么这个 ?
更新 ==============================
使用boost::thread库(升级版本:1.60),
替换std::thread为boost::thread,并建立静态链接,
g++ -pthread -o one1 one.cpp -Wall -std=c++11 -O3 -I /opt/boost/include/ -L /opt/boost/lib/ -lboost_system -lboost_thread -static
没问题!
困惑...
Phi*_*ßen 45
首先,解决方案.这将是有效的:
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -lrt -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
Run Code Online (Sandbox Code Playgroud)
当你使用时-lrt,编译器已经链接到pthread(并且根据平台,它确实定义了额外的宏-pthread,请参阅此问题以获取更多详细信息).
所以如果-D_REENTRANT暗示-pthread,你为什么需要指定-lpthread何时静态链接?那怎么-lpthread办?
在Unix上,使用ELF文件格式,它具有弱符号和强符号的概念.引用维基百科页面:
默认情况下,如果没有任何注释,则目标文件中的符号很强.在链接期间,强符号可以覆盖同名的弱符号.相反,共享名称的两个强符号在链接时产生链接错误.
动态和静态库有一个细微的区别.在静态库中,链接器将停在第一个符号,即使它是一个弱符号,并停止寻找强符号.要强制它查看所有符号(就像它对动态链接库所做的那样),Wl,--whole-archive支持该ld选项.
引用来自--whole-archive:
man ld对于--whole-archive选项后命令行中提到的每个归档,请在链接中包含归档中的每个目标文件,而不是在归档中搜索所需的目标文件.这通常用于将存档文件转换为共享库,从而强制将每个对象包含在生成的共享库中.此选项可能不止一次使用.
它继续通过从gcc解释,您必须将选项传递为--whole-archive::
从gcc使用此选项时的两个注意事项:首先,gcc不知道此选项,因此您必须使用-Wl,-whole-archive.其次,不要忘记在归档列表之后使用-Wl,-no-whole-archive,因为gcc会将自己的归档列表添加到您的链接中,您可能也不希望此标记也影响这些归档.
它再次解释了如何关闭它:
-Wl,--whole-archive关闭后续存档文件的--whole-archive选项的效果.
弱符号的一个用例是能够用优化的符号交换实现.另一种是使用存根,如果需要可以在以后更换.
例如,POSIX要求--no-whole-archive:(在概念上使用fputc)是线程安全的并且需要同步,这是昂贵的.在单线程环境中,您不希望支付成本.因此,实现可以将同步函数实现为空存根,并将函数声明为弱符号.
稍后,如果链接多线程库(例如,pthread),则很明显不支持单线程支持.链接多线程库时,链接器可以通过实际同步函数(定义为强符号并由线程库实现)替换存根.另一方面,如果没有链接多线程库,则可执行文件将使用存根来实现同步功能.
glibc(提供printf)和pthreads似乎正好使用这个技巧.有关详细信息,请参阅有关glibc中弱符号用法的此问题.上面的例子来自这个答案.
nm允许您详细查看它,这与上面引用的答案一致:
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
Run Code Online (Sandbox Code Playgroud)
"w"代表"弱",因此静态链接的libc库包含fputc弱符号.静态链接的pthread库将其包含为强符号:
$ nm /usr/lib/libc.a 2>/dev/null | grep pthread_mutex_lock
w __pthread_mutex_lock
... (repeats)
Run Code Online (Sandbox Code Playgroud)
通过查看动态链接的可执行文件的共享库依赖项,我得到的__pthread_mutex_lock机器输出几乎相同:
$ nm /usr/lib/libpthread.a 2>/dev/null | grep pthread_mutex_lock
U pthread_mutex_lock
pthread_mutex_lock.o:
00000000000006a0 T __pthread_mutex_lock
00000000000006a0 T pthread_mutex_lock
0000000000000000 t __pthread_mutex_lock_full
Run Code Online (Sandbox Code Playgroud)
使用ltrace打印库调用,会产生以下输出:
$ ldd one
linux-vdso.so.1 (0x00007fff79d6d000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fcaaeeb3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fcaaeb9b000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fcaae983000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fcaae763000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcaae3bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaaf23b000)
Run Code Online (Sandbox Code Playgroud)
例如,ldd被调用,很可能在std::thread::join内部使用.该符号可以在pthread_join输出中列出的(动态链接的)库中找到,即in ldd和libstdc++.so.6:
$ ltrace -C ./one
std::ios_base::Init::Init()(0x563ab8df71b1, 0x7ffdc483cae8, 0x7ffdc483caf8, 160) = 0
__cxa_atexit(0x7fab3023bc20, 0x563ab8df71b1, 0x563ab8df7090, 6) = 0
operator new(unsigned long)(16, 0x7ffdc483cae8, 0x7ffdc483caf8, 192) = 0x563ab918bc20
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2f6a1fb0, 0, 0x800000) = 0x563ab918bd70
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2eea0fb0, 0, 0x800000) = 0x563ab918bec0
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
) = 0
operator new(unsigned long)(16, 0x7fab2e69ffb0, 0, 0x800000) = 0x563ab918c010
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
test start
) = 0
std::thread::join()(0x7ffdc483c9a0, 0x7fab2de9efb0, 0, 0x800000test start
test release
test release
test release
test release
test end
test end
test end
test end
) = 0
std::thread::join()(0x7ffdc483c9a8, 0x7fab2eea19c0, 0x7fab2f6a2700, 0) = 0
std::thread::join()(0x7ffdc483c9b0, 0x7fab2e6a09c0, 0x7fab2eea1700, 0) = 0
std::thread::join()(0x7ffdc483c9b8, 0x7fab2de9f9c0, 0x7fab2e6a0700, 0) = 0
+++ exited (status 0) +++
Run Code Online (Sandbox Code Playgroud)
在动态链接的可执行文件中,链接器将用强符号替换弱符号.在此示例中,我们必须为静态链接库强制执行相同的语义.这就是为什么libpthread.so.0需要.
找出它有点试错.至少,我没有找到关于该主题的明确文件.我认为这是因为Linux上的静态链接已成为一种边缘情况,而动态链接通常是如何使用库的规范方法(有关比较,请参阅静态链接与动态链接).我看到的最极端的例子,并且在一段时间内努力使其工作是静态链接TBB.
如果您使用autotools作为构建系统,则需要一种解决方法,因为automake不允许您在LDADD中设置选项.不幸的是,你不能写:
$ nm /usr/lib/libstdc++.so.6 | grep pthread_join
w pthread_join
$ nm /usr/lib/libpthread.so.0 | grep pthread_join
0000000000008280 T pthread_join
Run Code Online (Sandbox Code Playgroud)
作为一种解决方法,您可以通过在configure.ac中定义标志来避免检查,并使用它们,如下所示:
(Makefile.am)
mytarget_LDADD = -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7696 次 |
| 最近记录: |