Thread Local Storage理解
带着问题去学习
1. 什么是thread local storage?
一种计算机编程方法,使用线程本地静态或全局的内存。
2. 主要作用是什么?
- 避免资源竞争;当多个线程访问同一个资源时,会产生竞争。当将资源声明为thread local storage时,则不会有竞争。
- 使用全局对象方法的重入性;比如一个函数使用全局变量设置一个错误码(比如c库中的errno),如果errno是个全局变量,一个系统方法会重写这个值之前刚被另外一个线程修改,然而另一个线程的代码马上又对errno进行校验使用(此时结果不符合预期);使用thread local storage可以解决:使errno看起来是个全局变量,但是每个线程拥有一个。
3. 编译之后存放在什么段?
编译之后存放在TLS section,如果没有初始值,则在.tbss;如果有初始值,则在.tdata;
#include <stdio.h>
#include <thread>
thread_local int hello = 3;
int main(int argc, char** argv){
printf("hello:%d\n",hello);
return 0;
}
-
使用readelf -s 查看hello符号的位置(首先将上述代码编译成main二进制)
readelf -s main | grep -E ‘hello|Num’
输出:
Num: Value Size Type Bind Vis Ndx Name Num: Value Size Type Bind Vis Ndx Name 58: 0000000000000000 4 TLS GLOBAL DEFAULT 21 hello
-
Ndx表示符号所属的段,使用readelf -S 查看21 是什么段
readelf -S main | grep -A 1 -E ‘[21|Name’
输出
[Nr] Name Type Address Offset Size EntSize Flags Link Info Align -- [21] .tdata PROGBITS 0000000000003db4 00002db4 0000000000000004 0000000000000000 WAT 0 0 4
所以thread_local变量hello的符号类型为TLS,全局作用域,位于.tdata段中。
ps: 当thread_local变量没有初始化时,位于.tbss段(和全局变量类似,初始化的全局变量位于.data段,未初始化的全局变量位于.bss段), 感兴趣的可以将thread_local int hello = 3;改为thread_local int hello;然后再按照上面步骤进行查看。
编译之后存放在什么段?
答案:初始化的thread_local变量编译过后位于.tdata段,未初始化的位于.tbss段。
4. 运行时如何进行初始化,存放在内存的什么区域?
线程使用变量时,从相应数据段中复制数据,然后存放在thread local storage区域。