转自: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. 配置vim nginx.conf高亮

    #!/bin/bashwget http://www.vim.org/scripts/download_script.php?src_id=14376 -O nginx.vimmv nginx.vim ...

  2. Vue之简易的留言板功能

    今天我将带大家通过Vue的todolist案例来完成一个简易的网页留言板! LES'T GO! 首先我们需要在页面上搭建一个input文本输入框,并设置提交按钮,通过循环指令来完成输入框的信息提交! ...

  3. Flask初学者:URL(传参,请求,重定向)

    URL传参: 良好的URL:视图函数对应的url以/结尾是一种良好url,因为用户在访问的时候无论他有没有加上最后这个斜杠,都是能访问到的,相反,视图函数的url没有以/结尾,用户访问的时候却加上了这 ...

  4. CDOJ:1636-梦后楼台高锁,酒醒帘幕低垂(Kruskal+暴力)

    梦后楼台高锁,酒醒帘幕低垂 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submit ...

  5. BFS:胜利大逃亡

    解题心得: 1.水题,主要主意好一个点就好. 2.注意x.y.z坐标的选取就好. 题目: Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会. 魔王住在一个城堡里,城 ...

  6. poj 3273 分期问题 最大化最小值

    题意:将N个账款分给城M个财务期,使得每个分期账款和的值最大? 思路: 每次mid为分期账款 如果分期次数小于m说明mid太大,减上限  反正 增下限 开始下限设为 最大值 上限设为和 解决问题的代码 ...

  7. TCP/IP网络编程之套接字与标准I/O

    标准I/O函数 标准标准I/O函数有两个优点: 标准I/O函数具有良好的移植性 标准I/O函数可以利用缓冲提高性能 关于移植性无需过多解释,不仅是I/O函数,所有标准函数都具有良好的移植性.因为,为了 ...

  8. csu-2018年11月月赛Round2-div2题解

    csu-2018年11月月赛Round2-div2题解 A(2193):昆虫繁殖 Description 科学家在热带森林中发现了一种特殊的昆虫,这种昆虫的繁殖能力很强.每对成虫过x个月产y对卵,每对 ...

  9. 混淆矩阵、准确率、召回率、ROC曲线、AUC

    混淆矩阵.准确率.召回率.ROC曲线.AUC 假设有一个用来对猫(cats).狗(dogs).兔子(rabbits)进行分类的系统,混淆矩阵就是为了进一步分析性能而对该算法测试结果做出的总结.假设总共 ...

  10. Git 笔记 - section 1

    1. 创建版本库 创建目录 git init git add <file> git commit -m "本次提交内容的说明" 2. 查看状态 git status g ...