转自:http://www.cnblogs.com/Swartz/articles/3939382.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 errno to 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.

参考


  1. http://stackoverflow.com/questions/6266183/does-linking-an-lpthread-changes-application-behaviour-linux-glibc
  2. http://stackoverflow.com/questions/21092601/is-pthread-in-glibc-so-implemented-by-weak-symbol-to-provide-pthread-stub-functi
  3. http://stackoverflow.com/questions/11161462/why-glibc-and-pthread-library-both-defined-same-apis/11210463#11210463
  4. http://stackoverflow.com/questions/21092601/is-pthread-in-glibc-so-implemented-by-weak-symbol-to-provide-pthread-stub-functi
  5. http://www.gnu.org/software/libc/manual/html_node/Porting.html

编译程序加不加 -lpthread 的区别【转】的更多相关文章

  1. shell脚本加不加export的区别

    加了export: jackyyu@ubuntu:~$ cat 1.sh #!/bin/dash test=test echo ${test} echo ${TERM} TERM=dumb expor ...

  2. JavaScript函数后面加不加括号的区别

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  3. JAVA中,一个类中,方法加不加static的区别,

    通俗理解: 1.若是对象的特有行为,(也就是某个实例方法特有的行为),不加static 2. 若是对象集合共有的集合,则加static static类型方法只可以访问静态变量和方法 实例方法可以访问实 ...

  4. C++中创建对象的时候加括号和不加括号的区别

    c++创建对象的语法有----- 1 在栈上创建 MyClass a; 2 在堆上创建加括号 MyClass *a= new MyClass(); 3 不加括号 MyClass *a = new My ...

  5. C++中创建对象的时候加括号和不加括号的区别(转)

    c++创建对象的语法有----- 1 在栈上创建 MyClass a; 2 在堆上创建加括号 MyClass *a= new MyClass(); 3 不加括号 MyClass *a = new My ...

  6. scanf加不加\n?

    近两天用vs2013敲代码碰到的问题 关于scanf小括号中加不加\n的区别 例程序如下所示: 第一个程序: int main(){ ; printf("你会去敲代码吗?(选择1 or 0) ...

  7. Java中主类中定义方法加static和不加static的区别

     Java中主类中定义方法加static和不加static的区别(前者可以省略类名直接在主方法调用(类名.方法),后者必须先实例化后用实例调用) 知识点:1.Getter and Setter 的应用 ...

  8. js中加“var”和不加“var”的区别

    JavaScript 拥有动态类型.这意味着相同的变量可用作不同的类型: var x // x 为 undefined var x = 6; // x 为数字 var x = "Bill&q ...

  9. 【转】new对象时,类名后加括号和不加括号的区别

    请看测试代码: #include <iostream> using namespace std; // 空类 class empty { }; // 一个默认构造函数,一个自定义构造函数 ...

随机推荐

  1. Zimber 8.8.12卸载后重新安装报错解决办法

    1.1  zimber故障处理步骤 1.1.1  现象描述 Running Post Installation Configuration: /opt/zimbra/bin/zmlocalconfig ...

  2. MySQL之索引(二)

    高性能的索引策略 正确地创建和使用索引是实现高性能查询的基础.在MySQL之索引(一)这一章中我们介绍了各种类型的索引及其对应的优缺点.现在我们一起来看看如何真正地发挥这些索引的优势. 独立的列 我们 ...

  3. Vs2012 打开项目 自动关闭 并停止工作 解决方法

    来源:http://q.cnblogs.com/q/52530/ http://www.microsoft.com/zh-cn/download/details.aspx?id=36020 下载并安装 ...

  4. loj2043 「CQOI2016」K 远点对

    k-d tree 裸题------ #include <algorithm> #include <iostream> #include <cstdio> using ...

  5. NOI p 2017 TG游记

    嗨小朋友们大家好 还记得我是谁吗 对了我就是为iot配音的演员 弹鸡鸡 今天呐我特别的要向长沙市的oier们 洛谷的oier们 还有cnblogs的oier们问声好 为什么呢 因为我们在2017年11 ...

  6. Python框架之Django学习笔记(二)

    安装Django 我是在windows下安装的python以及django,下面的链接可以下载Django: http://www.djangoproject.com/download/ 1.下载 D ...

  7. ADO之密码验证--3次错误就锁定『改进』

    这里使用了SqlHelper,简化程序 自己写一个SqlHelper,把数据库的连接等都写到里面去. 首先把连接字符串添加到配置文件里去,右键解决方案-->添加新建项-->选择应用程序配置 ...

  8. 移动web前端开发小结

    注意:Chrome模拟手机的显示的界面是有误差的,强烈建议一定要在真机测试自己的移动端页面(以移动端页面为准). 1.页面高度渲染错误,页面的高度是否包含了导航,(华为手机就是偏偏有底部菜单) 设置窗 ...

  9. Github问题An error occurred trying to download

    Github for windows安装过程出现了这样的问题An error occurred trying to download 'http://github-windows.s3.amazona ...

  10. Python+Selenium中级篇之-封装一个自己的类-浏览器引擎类

    前一篇文章我们知道了,如何去封装几个简单的Selenium方法到我们自定义的类,这次我们编写一个类,叫浏览器引擎类,通过更改一个字符串的值,利用if语句去判断和控制启动那个浏览器.这里我们暂时,支持三 ...