编译程序加不加 -lpthread 的区别【转】
2017-05-11 14:14
169 查看
转自:http://www.cnblogs.com/Swartz/articles/3939382.html
作者:Lokki 出处:http://www.cnblogs.com/Swartz/ 欢迎转载,也请保留这段声明。谢谢!
在之后的楼层讨论,大家发现在编译以上代码时候加 -lpthread 和不加 -lpthread 得出了截然不同的结果。这是为什么呢?
本文主要讨论动态链接编译的方式。
很显然,test2链接的动态库里面没有pthread。我们看一下libc.so里面的符号是不是有pthread_mutex_lock函数。
原来在libc.so库里面有这些函数,这样test2就可以正确编译执行了。
显然,test1的结果表明了局部mutex的状态可以被子进程继承,test2的结果却恰恰相反。这是因为test1调用的pthread_mutex_*函数是来自于pthread库,test2调用的函数来自libc.so库。libc.so库里面的pthread_mutex_*函数什么都没有做,只是返回了0。这样就会出现上述结果。
libc之所以这样做是因为一些库需要做到线程安全,但是自身却不使用线程。试想,一个库的函数需要使用mutex,当该函数调用时候需要lock和unlock。这样在程序为单线程时候不必链接pthread库这个函数仍然可以正常调用,事实上lock和unlock的动作不会有任何效果。在多线程时候,程序链接了pthread库,这样函数就可以正常地lock和unlock,实现线程安全的特性。
例如,根据posix标准,你每次调用
很明显,pthread的相关函数都被定义为了弱符号,而这些函数在libpthread.a里面都被定义为强符号。这样在程序链接pthread时候会调用pthread的强符号,没有链接pthread时候会调用libc定义的函数。
GUN对stub的描述:
A stub function is a function which cannot be implemented on a particular machine or operating system. Stub functions always return an error, and set
http://stackoverflow.com/questions/21092601/is-pthread-in-glibc-so-implemented-by-weak-symbol-to-provide-pthread-stub-functi
http://stackoverflow.com/questions/11161462/why-glibc-and-pthread-library-both-defined-same-apis/11210463#11210463
http://stackoverflow.com/questions/21092601/is-pthread-in-glibc-so-implemented-by-weak-symbol-to-provide-pthread-stub-functi
http://www.gnu.org/software/libc/manual/html_node/Porting.html
分类: 多线程编程,链接装载与库
作者:Lokki 出处:http://www.cnblogs.com/Swartz/ 欢迎转载,也请保留这段声明。谢谢!
讨论贴
最近在CSDN上看到一个帖子在讨论 进程间共享的Posix mutex的锁定状态能否被子进程继承?,其中4楼的帖子给出了一个测试局部mutex能否被继承的例子:1 #include <pthread.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 6 int main(void) 7 { 8 pid_t pid; 9 pthread_mutex_t mut; 10 11 pthread_mutex_init(&mut, NULL); 12 13 printf("lock\n"); 14 pthread_mutex_lock(&mut); 15 16 printf("fork\n"); 17 pid = fork(); 18 if( pid == 0 ) // 子进程尝试锁定 19 { 20 printf("child: lock\n"); 21 pthread_mutex_lock(&mut); 22 printf("child: over\n"); 23 24 exit(0); 25 } 26 27 pthread_mutex_destroy(&mut); 28 return(0); 29 }
在之后的楼层讨论,大家发现在编译以上代码时候加 -lpthread 和不加 -lpthread 得出了截然不同的结果。这是为什么呢?
1 gcc -o test1 main.c -lpthread 2 gcc -o test2 main.c
本文主要讨论动态链接编译的方式。
为什么加不加 -lpthread 都可以编译通过且成功执行
由于程序正确地添加了头文件 pthread.h,所以在编译的链接阶段之前,加不加 -lpthread 生成的目标文件是没有区别的,区别在于编译阶段的链接过程。程序里面的pthread_mutex_init pthread_mutex_lock 等函数(事实上除了main函数之外的函数都是)是未定义的符号。编译器需要在链接期间的正确地解析未定义符号的地址。那么对于test2中的pthread_mutex_lock函数,连接器能正确解析到吗?我们先来看一下test1和test2都链接了哪些动态库(注意链接库的顺序)。很显然,test2链接的动态库里面没有pthread。我们看一下libc.so里面的符号是不是有pthread_mutex_lock函数。
原来在libc.so库里面有这些函数,这样test2就可以正确编译执行了。
为什么程序运行的结果不一样?
在我们执行两个程序之后得到以下结果:显然,test1的结果表明了局部mutex的状态可以被子进程继承,test2的结果却恰恰相反。这是因为test1调用的pthread_mutex_*函数是来自于pthread库,test2调用的函数来自libc.so库。libc.so库里面的pthread_mutex_*函数什么都没有做,只是返回了0。这样就会出现上述结果。
为什么libc要定义一些多线程的函数?
我们再次查看libc.so定义的pthread有关的函数时候,可以找到很多熟悉的函数(没有pthread_create,为什么?)。libc之所以这样做是因为一些库需要做到线程安全,但是自身却不使用线程。试想,一个库的函数需要使用mutex,当该函数调用时候需要lock和unlock。这样在程序为单线程时候不必链接pthread库这个函数仍然可以正常调用,事实上lock和unlock的动作不会有任何效果。在多线程时候,程序链接了pthread库,这样函数就可以正常地lock和unlock,实现线程安全的特性。
例如,根据posix标准,你每次调用
fputc(ch, stream)都会有mutex的lock和unlock。
如何保证调用到有效的pthread函数?
1. 对于动态链接的程序
通过符号介入。符号介入是指:在动态链接时候,如果一个符号在多个库里面有定义,那么连接器将使用它第一次找到的版本。看第一个图,我们可以看到libpthread的链接顺序要比libc靠前,默认情况下libc都排在编译器链接顺序的最后一位。这样的话,如果程序没有链接pthread库,那么程序会调用libc的pthread函数。如果程序链接了pthread库,由于pthread的链接顺序总是排在libc之前,程序会调用pthread的函数。2. 对于静态链接的程序
之前我们讨论的是动态链接的程序,其中涉及到了动态链接符号的解析,由于静态链接程序没有这个步骤,所以静态链接程序不能通过这个来实现。我们可以看一下libc.a里面的pthread函数:很明显,pthread的相关函数都被定义为了弱符号,而这些函数在libpthread.a里面都被定义为强符号。这样在程序链接pthread时候会调用pthread的强符号,没有链接pthread时候会调用libc定义的函数。
3. 符号版本的作用
情况比较少,暂时忽略后记
通过对现象的深入剖析,看到了libc库的强大。事实上,libc除了pthread相关函数还实现了其他的一些函数,这些函数称为stubs。他们不会实现实际的功能,只是一个占位符(place holder),当有真正的函数可用时候,他们就会让出自己的位置。GUN对stub的描述:
A stub function is a function which cannot be implemented on a particular machine or operating system. Stub functions always return an error, and set
errnoto
ENOSYS(Function not implemented). See Error Reporting. If you define a stub function, you must place the statement
stub_warning(function
), where function is the name of your function, after its definition. This causes the function to be listed in the installed
<gnu/stubs.h>, and makes GNU ld warn when the function is used.
参考
http://stackoverflow.com/questions/6266183/does-linking-an-lpthread-changes-application-behaviour-linux-glibchttp://stackoverflow.com/questions/21092601/is-pthread-in-glibc-so-implemented-by-weak-symbol-to-provide-pthread-stub-functi
http://stackoverflow.com/questions/11161462/why-glibc-and-pthread-library-both-defined-same-apis/11210463#11210463
http://stackoverflow.com/questions/21092601/is-pthread-in-glibc-so-implemented-by-weak-symbol-to-provide-pthread-stub-functi
http://www.gnu.org/software/libc/manual/html_node/Porting.html
分类: 多线程编程,链接装载与库
相关文章推荐
- 编译IA64 X64程序的区别
- LINUX中编译程序时,-I,-L,-l 的区别
- 编译成release版本与debug版本的程序有何执行上的区别?
- tc编译的dos程序和vc编译的win32控制台程序的区别
- 注意:windos cmd下编译java程序与eclipse下编译的区别
- 汇编程序与编译程序区别 assembler compiler
- 编译参数中-pthread以及-lpthread的区别
- 数据结构中和c/C++编译的程序占用的内存中的堆,栈的区别与联系
- Java与C++程序在编译和运行上的区别
- java与c++程序在编译和运行上有什么区别
- 解释程序和编译程序的区别
- 终于明白了tc编译的dos程序和vc编译的win32控制台程序的区别
- vs2010 MFC程序编译过程中debug版本跟release版本的区别
- 解释程序与编译程序的区别
- 程序的编译与解释有什么区别?
- 预处理标识符,预处理与函数的相关的区别;程序的编译与链接的过程
- 关于myeclipse+tomcate和手动编译程序+tomcate两者运行web工程的区别
- 由C/C++编译的程序占用的内存分配-堆与栈的区别
- Linux通过源码编译安装程序;yum和源码安转软件包的区别
- 解释程序与解释程序的缺点,图解——解释程序与编译程序的区别