fbpx
维基百科

线程局部存储

线程局部存储 (TLS) 是一种存储持续期(storage duration),对象的存储是在线程开始时分配,线程结束时回收,每个线程有该对象自己的实例。这种对象的链接性(linkage)可以是静态的也可是外部的。

TLS的一个例子是用全局变量errno英语errno表示错误号。这可能在多线程并发时产生同步错误。线程局部存储的errno是个解决办法。

Windows的实现 编辑

每个进程都有一组标志,共TLS_MINIMUM_AVAILABLE(==64)个。每个标志可以被设为FREE或INUSE,表示该TLS元素是否正在使用。注意这组标志属进程所有。当系统创建一个线程的时候,会为该线程分配与线程关联的、属于线程自己的PVOID型数组(共有TLS_MINIMUM_AVAILBALE个元素),数组中的每个PVOID可以保存任意值。

Windows API函数TlsAlloc用于获取进程中一个未用的TLS slot index。然后将该标志从FREE改为INUSE,并返回该标志在位数组中的索引,通常将该索引保存在一个全局变量中,因为这个值会在整个进程范围内(而不是线程范围内)使用。

调用TlsSetValue(dwTlsIndex,pvTlsValue)将一个PVOID值放到线程的数组中dwTlsIndex指定的具体位置。

函数TlsGetValueTlsSetValue用于通过TLS slot index读写一个线程局部存储变量所指向的内存块。函数TlsFree用于释放TLS slot index

Win32线程信息块英语Win32 Thread Information Block的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定义了线程特定的数据。

函数pthread_key_createpthread_key_delete创建与删除一个键,用于线程特定的数据。键的类型被称为pthread_key_t。键可以被所有线程看到。在每个线程,键可以用pthread_setspecific函数关联到线程特定的数据。数据可以随后用pthread_getspecific函数获取。

特定于语言的实现 编辑

C and C++ 编辑

C11的关键字_Thread_local用于定义线程局部变量。在头文件<threads.h>定义了thread_local为上述关键词的同义。例如:

#include <threads.h> thread_local int foo = 0; 

C++11引入了thread_local[2]关键字用于下述情形:

  • 命名空间(全局)变量
  • 文件静态变量
  • 函数静态变量
  • 静态成员变量

此外,不同编译器提供了各自的方法声明线程局部变量:

Windows的版本早于Vista与Server 2008, __declspec(thread)对于DLL只用于DLL被可执行程序绑定静态加载,在LoadLibrary()函数动态加载DLL将报告protection fault或data corruption。[9]

Java 编辑

Java语言中,线程局部变量使用ThreadLocal类对象表示。ThreadLocal保持了变量的类型T,可以通过get/set方法访问。例如,ThreadLocal保持了Integer值:

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.

Python 编辑

Python语言从版本2.4开始,threading模块的local类可用于创建线程局部存储:

import threading mydata = threading.local() mydata.x = 1 

Ruby 编辑

Ruby语言能创建/访问线程局部变量使用[]=/[]方法:

Thread.current[:user_id] = 1 

参考文献 编辑

  1. ^ Pietrek, Matt. . MSDN. May 2006 [6 April 2010]. (原始内容存档于2016-03-03). 
  2. ^ Section 3.7.2 in C++11 standard
  3. ^ IBM XL C/C++: Thread-local storage (页面存档备份,存于互联网档案馆
  4. ^ GCC 3.3.1: Thread-Local Storage (页面存档备份,存于互联网档案馆
  5. ^ Clang 2.0: release notes (页面存档备份,存于互联网档案馆
  6. ^ Intel C++ Compiler 8.1 (linux) release notes: Thread-local Storage (页面存档备份,存于互联网档案馆
  7. ^ Visual Studio 2003: Thread extended storage-class modifier (页面存档备份,存于互联网档案馆
  8. ^ Intel C++ Compiler 10.0 (Windows平台): Thread-local storage (页面存档备份,存于互联网档案馆
  9. ^ . [2018-09-13]. (原始内容存档于2008-04-04). 
  10. ^ . Stack Overflow. Stack Exchange. [27 December 2015]. (原始内容存档于2020-08-09). 

外部链接 编辑

  • ELF Handling For Thread-Local Storage (页面存档备份,存于互联网档案馆) — Document about an implementation in C or C++.
  • Article "Use thread-local Storage to Pass Thread Specific Data (页面存档备份,存于互联网档案馆)" by Doug Doedens
  • "Thread-Local Storage (页面存档备份,存于互联网档案馆)" by Lawrence Crowl
  • Article "It's Not Always Nice To Share (页面存档备份,存于互联网档案馆)" by Walter Bright
  • Practical ThreadLocal usage in Java:
  • GCC "[1] (页面存档备份,存于互联网档案馆)"

线程局部存储, 是一种存储持续期, storage, duration, 对象的存储是在线程开始时分配, 线程结束时回收, 每个线程有该对象自己的实例, 这种对象的链接性, linkage, 可以是静态的也可是外部的, tls的一个例子是用全局变量, span, class, data, orig, title, errno, data, lang, code, data, lang, name, 英语, data, foreign, title, errno, span, class, page, errno, . 线程局部存储 TLS 是一种存储持续期 storage duration 对象的存储是在线程开始时分配 线程结束时回收 每个线程有该对象自己的实例 这种对象的链接性 linkage 可以是静态的也可是外部的 TLS的一个例子是用全局变量 span class ilh all data orig title errno data lang code en data lang name 英语 data foreign title errno span class ilh page errno span span class noprint ilh comment span class ilh lang 英语 span span class ilh colon span span class ilh link span lang en dir auto errno span span span span 表示错误号 这可能在多线程并发时产生同步错误 线程局部存储的errno是个解决办法 目录 1 Windows的实现 2 Pthreads的实现 3 特定于语言的实现 3 1 C and C 3 2 Java 3 3 NET 语言 C 与Visual Basic Net 3 4 Python 3 5 Ruby 4 参考文献 5 外部链接Windows的实现 编辑每个进程都有一组标志 共TLS MINIMUM AVAILABLE 64 个 每个标志可以被设为FREE或INUSE 表示该TLS元素是否正在使用 注意这组标志属进程所有 当系统创建一个线程的时候 会为该线程分配与线程关联的 属于线程自己的PVOID型数组 共有TLS MINIMUM AVAILBALE个元素 数组中的每个PVOID可以保存任意值 Windows API函数TlsAlloc用于获取进程中一个未用的TLS slot index 然后将该标志从FREE改为INUSE 并返回该标志在位数组中的索引 通常将该索引保存在一个全局变量中 因为这个值会在整个进程范围内 而不是线程范围内 使用 调用TlsSetValue dwTlsIndex pvTlsValue 将一个PVOID值放到线程的数组中dwTlsIndex指定的具体位置 函数TlsGetValue与TlsSetValue用于通过TLS slot index读写一个线程局部存储变量所指向的内存块 函数TlsFree用于释放TLS slot index 在Win32线程信息块 英语 Win32 Thread Information Block 的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定义了线程特定的数据 函数pthread key create与pthread key delete创建与删除一个键 用于线程特定的数据 键的类型被称为pthread key t 键可以被所有线程看到 在每个线程 键可以用pthread setspecific函数关联到线程特定的数据 数据可以随后用pthread getspecific函数获取 特定于语言的实现 编辑C and C 编辑 C11的关键字 Thread local用于定义线程局部变量 在头文件 lt threads h gt 定义了thread local为上述关键词的同义 例如 include lt threads h gt thread local int foo 0 C 11引入了thread local 2 关键字用于下述情形 命名空间 全局 变量 文件静态变量 函数静态变量 静态成员变量此外 不同编译器提供了各自的方法声明线程局部变量 Solaris Studio C C IBM XL C C 3 GNU C 4 Clang 5 与Intel C Compiler Linux平台 6 使用语法 thread int number Visual C 7 Intel C C Windows systems 8 C Builder 与Digital Mars C 使用语法 declspec thread int number C Builder也可以使用语法 int thread number Windows的版本早于Vista与Server 2008 declspec thread 对于DLL只用于DLL被可执行程序绑定静态加载 在LoadLibrary 函数动态加载DLL将报告protection fault或data corruption 9 Java 编辑 Java语言中 线程局部变量使用ThreadLocal类对象表示 ThreadLocal保持了变量的类型T 可以通过get set方法访问 例如 ThreadLocal保持了Integer值 private static final ThreadLocal lt Integer gt myThreadLocalInteger new ThreadLocal lt Integer gt Oracle OpenJDK使用操作系统线程以避免性能代价 10 NET 语言 C 与Visual Basic Net 编辑 NET Framework语言 静态域可标记ThreadStatic attribute 页面存档备份 存于互联网档案馆 class FooBar ThreadStatic static int foo NET 4 0 System Threading ThreadLocal lt T gt 页面存档备份 存于互联网档案馆 可用于分配与惰性装入线程局部变量 class FooBar private static System Threading ThreadLocal lt int gt foo Also an API is available for dynamically allocating thread local variables Python 编辑 Python语言从版本2 4开始 threading模块的local类可用于创建线程局部存储 import threading mydata threading local mydata x 1 Ruby 编辑 Ruby语言能创建 访问线程局部变量使用 方法 Thread current user id 1参考文献 编辑 Pietrek Matt Under the Hood MSDN May 2006 6 April 2010 原始内容存档于2016 03 03 Section 3 7 2 in C 11 standard IBM XL C C Thread local storage 页面存档备份 存于互联网档案馆 GCC 3 3 1 Thread Local Storage 页面存档备份 存于互联网档案馆 Clang 2 0 release notes 页面存档备份 存于互联网档案馆 Intel C Compiler 8 1 linux release notes Thread local Storage 页面存档备份 存于互联网档案馆 Visual Studio 2003 Thread extended storage class modifier 页面存档备份 存于互联网档案馆 Intel C Compiler 10 0 Windows平台 Thread local storage 页面存档备份 存于互联网档案馆 Rules and Limitations for TLS 2018 09 13 原始内容存档于2008 04 04 How is Java s ThreadLocal implemented under the hood Stack Overflow Stack Exchange 27 December 2015 原始内容存档于2020 08 09 外部链接 编辑ELF Handling For Thread Local Storage 页面存档备份 存于互联网档案馆 Document about an implementation in C or C ACE TSS lt TYPE gt Class Template Reference RWTThreadLocal lt Type gt Class Template Documentation Article Use thread local Storage to Pass Thread Specific Data 页面存档备份 存于互联网档案馆 by Doug Doedens Thread Local Storage 页面存档备份 存于互联网档案馆 by Lawrence Crowl Article It s Not Always Nice To Share 页面存档备份 存于互联网档案馆 by Walter Bright Practical ThreadLocal usage in Java https web archive org web 20161220151503 https www captechconsulting com blogs a persistence pattern using threadlocal and ejb interceptors GCC 1 页面存档备份 存于互联网档案馆 取自 https zh wikipedia org w index php title 线程局部存储 amp oldid 72658987, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。