之前在linux下做过一个测试:
写一个so,该so中有一个全局变量。so中的代码在运行时会修改该全局变量的值。然后,有多个程序都需要该so,而且这些应用程序都启动了。此时,很显然so只被加载了一份,那么,当这么多程序在运行调用该so时,该so中的全局变量的值会被覆盖来覆盖去么?
答案是不会。这是测试的答案。
现在知道原理了,尽管这是windows via C/C++中解释的windows的做法,但是我想linux也是这么类似处理的。
windows 使用memory map来加载exe和dll。当一个exe/dll有多个instance要启动时,实际在windows paging file(包括RAM和swap文件)中,exe和牵涉到的dll,只有一份。这样可以节省内存使用,也可以提高性能。
也就是说,如果是exe,虽然每个instance都有自己独立的地址空间,但是地址空间映射到storage的时候,他们映射的都是同样的地方。这样就带来问题了:exe/dll中的全局变量和静态变量怎么办?每个instance都有可能会修改这些变量。
windows 的做法是,该存放全局变量和静态变量的page,设定copy on write protect attribute。所以,当任何一个线程尝试修改这些page中的内容时,windows负责分配一个新的page出来,然后修改该线程的地址空间,将 这个新分配的page的地址设置上去,从此以后,该线程修改这个全局变量或是静态变量,操作的就是这个新分配的page了。这样,多个实例就不会出现全局 变量或静态变量互相覆盖的问题了。
参考windows via C/C++ P593,有详细说明。
曾经在一次写程序的时候,全局使用一个日志对象,所有的日志信息都由此日志对象写入文件。但是发现在动态链接库里,无法存取到该全局对象,后经查找资料。发现,动态链接库是否能存取主程序的全局变量,主程序是否能存取动态链接库里定义的全局变量都是可以通过链接指令改变此行为。
主程序存取动态链接库里的全局变量
例如动态库里定义全局变量int i, 在主程序里申明extern int i。 则,主程序存取的就是动态库里定义的i。在所有的UNIX平台上这是默认的行为(注意:实际定义i的 模块的点o文件,必须同时链接到动态库和主程序上,否则链接报错)。
如果不想让主程序能存取动态库里的全局变量,则在链接动态连接库的时候,给gcc传入-Wl,-Bsymbolic即可。
动态连接库存取主程序里定义的全局变量
在linux上,链接主程序的时候,使用参数-Wl,–export-dynamic
在AIX上,使用’deferred imports’ 并且 enable ‘runtime linking’.
PS:在linux 下 加入-export -dynamic 可以实现
https://www.cnblogs.com/super119/archive/2011/04/10/2011305.html
https://blog.csdn.net/liangyuannao/article/details/8086423
测试代码说明以下两个问题:
1. 工程
中
包含静态库A,
动态库
B,可执行程序C。C依赖于A和B,而B依赖于A。在A
中
定义有
全局变量
X(或类的静态成员变量),则在
动态库
B
中
访问的X,与可执行程序C
中
访问的X是同一个变量还是两个不同的变量?
答案:是两个不同的变量。
2. 工程
中
包含
动态库
A,
动态库
B,可执行程序C。C依赖于A和B,而B依赖于A。在A
中
定义有
全局变量
X(或类的静态成员变量),则在
动态库
B
中
访问的X,与可执行程序C
中
访问的X是同一个变量还是两个不同的变量?(注:所有库都在同一进程
中
使用)
答案:是共享同一个变量。即:在A是
动态库
的这种情况下,B和C访问到的X是同一变量。
博文地址:http://blog.csdn.net/guggy/article/details/8136325
或即时记:http://www.livelog.cn/bbs/viewthread.php?tid=16
也就是说,想要在so内实现一个不可重入的函数还是比较困难的,因为所有变量都是独立的,但是考虑如下场景:驱动层给了一个视频码流录制的接口,并且没有在驱动层做互斥,但实际上这个接口同一时间只可能被一个进程调用,那么很明显,串接到so
中
的接口必须实现该接口的原子调用。在应用程序编译的时候,不同的应用程序引用同一个库,那么
动态库
的代码是共享的。因为数据是独立的,代码是共享的。有了以上两个函数,其实就可以写一个so被加载时自动执行的初始化函数,这样可以保证so的使用者不必关心内存、锁的创建、销毁和使用。
关于static变量的生命周期。一般来说:static声明的变量初始化,只是在程序运行的第一次被执行。不过有例外,那就是如果该变量定义在dll内,那么该变量的初始化工作是在dll被装载时执行,在这种情况下,程序虽然只运行一次,但是该
静态变量
可能会被初始化好几次(与dll被装载的次数有关).这个问题本质上是:static声明的变量的生命周期与包含它的组件相关。从这个意义上,我们可以说,
在计算机科学里,静态库(英语:Static library, Statically-linked library),或称静态库,是一个外部函数与变量的集合体。静态库的文件内容,通常包含一堆程序员自定的变量与函数,其内容不像动.
一般的对象实例化在什么时候实例化的呢?
是不是在main函数运行到那里的时候,然后创建对象,会调用类里面的构造函数。
那当我们遇到全局/静态对象的时候,它是不是也是需要在main函数里面慢慢构造呢?
答案是 :
全局/静态对象 的构造函数调用实在main函数之前的。
有人在疑问?main函数之前还有函数?不是从main函数开始运行的吗?当然不是啦,明天揭晓这个秘密,今晚复习离散
一.静态库
全局变量
与当前应用
全局变量
重名编译出错,提示多次定义,因为静态可以看作本是应用的一部分,所以会报重定义.
二.
动态库
全局变量
与当前应用全局就量重名编译不会出错,当前应用
全局变量
覆盖
动态库
全局变量
.
三.静态库
全局变量
与
动态库
全局变量
重名编译不会出错,先链接谁,谁优先.如果多个静态库
全局变量
重名,编译出错.
四,
动态库
变量被多个进程使用会出现重入问题?不会.
当so被load的时候,会把s...
为了减少目标文件的尺寸,编译过程
中
gcc会移除掉static和inline的函数,链接过程
中
ld负责移除其它在最终代码
中
调用的函数。
实际上可能某函数在最终可执行程序
中
未被调用,但是某个dlopen的.so正好需要,就需要保留这个函数,使用-Wl,--whole-archive和 -Wl,--no-whole-archive 两个链接选项就能保证未调用函数不被优化掉。
http://