线程局部存储线程局部存储(英語:Thread-local storage,縮寫:TLS)是一种存储持续期(storage duration),对象的存储是在线程开始时分配,线程结束时回收,每个线程有该对象自己的实例。这种对象的链接性(linkage)可以是静态的也可是外部的。 TLS的一个例子是用全局变量 Windows的实现每个进程都有一组标志,共TLS_MINIMUM_AVAILABLE(==64)个。每个标志可以被设为FREE或INUSE,表示该TLS元素是否正在使用。注意这组标志属进程所有。当系统创建一个线程的时候,会为该线程分配与线程关联的、属于线程自己的PVOID型数组(共有TLS_MINIMUM_AVAILBALE个元素),数组中的每个PVOID可以保存任意值。 Windows API函数 调用TlsSetValue(dwTlsIndex,pvTlsValue)将一个PVOID值放到线程的数组中dwTlsIndex指定的具体位置。 函数 在Win32线程信息块的FS:[0x2C]地址处,存放的是线程局部存储表的地址。[1]每个线程用它自己的线程局部存储表的拷贝。TlsAlloc返回表中一个未使用的索引。因此每个线程可以用TlsSetValue(index)设置线程局部存储值,用TlsGetValue(index)获取线程局部存储值。 Windows可执行程序也可以定义一个节(section),映射到进程每个线程的不同的内存分页。这种节只定义在主程序里,动态链接库(DLL)不应该包含这种节因为不会被LoadLibrary函数在加载时初始化。 对于Windows系统来说,全局变量或静态变量会被放到".data"或".bss"段中,但当使用__declspec(thread)定义一个线程私有变量的时候,编译器会把这些变量放到PE文件的".tls"段中。当系统启动一个新的线程时,它会从进程的堆中分配一块足够大小的空间,然后把".tls"段中的内容复制到这块空间中,于是每个线程都有自己独立的一个".tls"副本。所以对于用__declspec(thread)定义的同一个变量,它们在不同线程中的地址都是不一样的。对于一个TLS变量来说,它有可能是一个C++的全局对象,那么每个线程在启动时不仅仅是复制".tls"的内容那么简单,还需要把这些TLS对象初始化,必须逐个地调用它们的全局构造函数,而且当线程退出时,还要逐个地将它们析构,正如普通的全局对象在进程启动和退出时都要构造、析构一样。Windows PE文件的结构中有个叫数据目录的结构。它总共有16个元素,其中有一元素下标为IMAGE_DIRECT_ENTRY_TLS,这个元素中保存的地址和长度就是TLS表(IMAGE_TLS_DIRECTORY结构)的地址和长度。TLS表中保存了所有TLS变量的构造函数和析构函数的地址,Windows系统就是根据TLS表中的内容,在每次线程启动或退出时对TLS变量进行构造和析构。TLS表本身往往位于PE文件的".rdata"段中。 Pthreads的实现Pthreads API定义了线程特定的数据。 函数 特定于语言的实现C and C++C11的关键字 #include <threads.h>
thread_local int foo = 0;
C++11引入了
此外,不同编译器提供了各自的方法声明线程局部变量:
Windows的版本早于Vista与Server 2008, JavaJava语言中,线程局部变量使用 private static final ThreadLocal<Integer> myThreadLocalInteger = new ThreadLocal<Integer>();
Oracle/OpenJDK使用操作系统线程以避免性能代价。[10] .NET 语言: C# 与Visual Basic.Net.NET Framework语言,静态域可标记ThreadStatic attribute (页面存档备份,存于互联网档案馆): class FooBar {
[ThreadStatic] static int foo;
}
.NET 4.0,System.Threading.ThreadLocal<T> (页面存档备份,存于互联网档案馆)可用于分配与惰性装入线程局部变量。 class FooBar {
private static System.Threading.ThreadLocal<int> foo;
}
Also an API is available for dynamically allocating thread-local variables. PythonPython语言从版本2.4开始,threading模块的local类可用于创建线程局部存储: import threading
mydata = threading.local()
mydata.x = 1
RubyRuby语言能创建/访问线程局部变量使用[]=/[]方法: Thread.current[:user_id] = 1
参考文献
外部链接
|
Portal di Ensiklopedia Dunia