Thread Local Storage理解

田鹤轩
2023-12-01

Thread Local Storage理解

带着问题去学习

1. 什么是thread local storage?

一种计算机编程方法,使用线程本地静态或全局的内存。

2. 主要作用是什么?

  1. 避免资源竞争;当多个线程访问同一个资源时,会产生竞争。当将资源声明为thread local storage时,则不会有竞争。
  2. 使用全局对象方法的重入性;比如一个函数使用全局变量设置一个错误码(比如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;
}
  1. 使用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
    
  2. 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区域。

 类似资料: