线程局部存储TLS, Thread Local Storage

TLS是C/C++运行库的一部分,而非操作系统的一部分。

分为动态TSL 和 静态TLS

一、动态TLS

应用程序通过调用一组4个函数来使用动态TLS, 这些函数实际上最为DLL所使用。

系统中的每个进程都有一组 正在使用标志(in-use flag), 每个标志可被设置为FREE 或者 INUSE, 表示该TLS元素是否正在使用。

微软平台保证至少有TLS_MINUMUM_AVALIABLE个标志位可供使用, TLS_MINUMUM_AVALIABLE在WinNT.h中被定义为64. 系统会在需要的时候分配更多的TLS元素,最多可达1000多个。

下面介绍下函数

DWORD    TlsAlloc();

这个函数让系统对进程中中的标志位进行检索并找到一个FREE标志,然后将该元素的标志从FREE置为INUSE, 并让TlsAlloc返回该元素的索引(下标)。

一个DLL(或应用程序)通常会将此索引保存在一个全局变量中,在整个进程范围内访问。

如果找不到一个标志为FREE的元素,则函数返回TLS_OUT_OF_INDEXES(在WinBase.h中被定义为0XFFFFFFFF)。

每个线程都有一个PVOID数组,每个线程使用每次TlsAlloc成功时的返回值作为各自线程中该数组的索引。

注意:该函数返回时会将每个线程中的数组对应的索引位置元素清零!

返回值:

失败:TLS_OUT_OF_INDEXES

成功:其他

BOOL    TlsSetValue(

DWORD   dwTlsIndex,   // TlsAlloc()函数的返回值

PVOID      pvTlsValue    //要设置的值

);

返回值:

TRUE: 成功

FALSE:失败

该函数的主调线程只能更改自己的数组,而不能修改其他线程的数组。

PVOID   TlsGetValue(

DWORD  dwTlsIndex    //TlsAlloc()函数的返回值

);

BOOL     TlsFree(

DWORD   dwTlsIndex    //TlsAlloc()函数的返回值

);

将该标志置为FREE, 并且将元素值清零。

二、静态TLS

__declspec(thread)   int  g_value = 0;

__declspec(thread)前缀是微软为VC++编译器增加的一个修饰符,它告诉编译器应该在可执行文件或DLL中,把对应的变量放到他自己的段中。

__declspec(thread)后面的变量必须声明为 全局变量 或 静态变量(全局或局部都可), 不可以将局部变量声明为__desclspec(thread)类型。

当编译器对程序进行编译的时候,会将所有TLS变量放到他自己的段中,这个段为.tls段。 链接器会将所有对象模块中的.tls段合并成一个大的.tls段,并将他保存到生成的exe或DLL文件中。

当系统将应用程序载入到内存的时候,会查看可执行文件中的.tls段,并分配一块足够的的内存来保存所有的静态TLS变量。 每当应用程序中的代码引用到这些变量之一事,相应的引用会被解析到刚分配的这块内存中的一个位置。 因此编译器必须生成额外的代码来引用静态TLS。

如果进程创建了一个新的线程,那么系统会得知这一情况并自动分配另一块内存来保存新线程的静态TLS变量。

当隐式加载DLL的时候:

如果exe使用了静态TLS, DLL也使用了TSL, 系统会首先确定exe的.tls段的大小,并将exe所有链接到的DLL的.tls段的大小相加。当系统在创建新线程的时候,会自动分配一块足够大的内存来保证应用程序和所有隐式链接的DLL需要的TLS变量。

当显式加载DLL的时候:

某DLL包含了静态TLS变量, exe使用LoadLibrary来显式加载DLL。 系统查看进程中已有线程,然后根据DLL中的TLS段扩大每个线程的TLS内存块。

当调用FreeLibrary释放DLL时,则该进程中的所有线程的TLS内存块也应该相应的缩减,缩减的部分是DLL中的TLS的部分。

转载于:https://www.cnblogs.com/cuish/p/3776246.html

【windows核心编程】线程局部存储TLS相关推荐

  1. Windows核心编程 - 线程池

    Windows提供了一个线程池机制来简化线程的创建.销毁及管理工作.有以下情形可使用线程池: 1. 以异步的方式来调用一个函数: 1)首先定义一个回调函数,函数原型: void NTAPI Simpl ...

  2. 转 windows核心编程 学习笔记 目录

    windows核心编程--SEH(结构异常处理) SEH 的工作原理.         Windows 程序设计中最重要的理念就是消息传递,事件驱动.当GUI应用程序触发一个消息时,系统将把该消息放入 ...

  3. 线程本地存储器——Windows核心编程学习手札之二十一

    线程本地存储器 --Windows核心编程学习手札之二十一 C/C++运行期库使用线程本地存储器,运行期库是在多线程应用程序出现前设计的,因此运行期库里的大多数函数是用于单线程应用程序的.函数strt ...

  4. [笔记]Windows核心编程《十六》线程栈

    系列文章目录 [笔记]Windows核心编程<一>错误处理.字符编码 [笔记]Windows核心编程<二>内核对象 [笔记]Windows核心编程<三>进程 [笔记 ...

  5. 线程的堆栈——Windows核心编程学习手札之十六

    线程的堆栈 --Windows核心编程学习手札之十六 系统会在进程的地址空间内保存一些区域,同时也会在进程地址空间内为线程的堆栈保留区域.线程都有自己的堆栈,创建时,系统就保留一个堆栈空间区域,并将相 ...

  6. 用户方式中线程的同步——Windows核心编程学习手札之八

    用户方式中线程的同步 --Windows核心编程学习手札之八 系统中所有线程都必须拥有对各种系统资源的访问权,这些资源包括内存堆栈.串口.文件.窗口和许多其他资源.如果一个线程需要独占对资源的访问权, ...

  7. 线程与内核对象的同步——Windows核心编程学习手札之九

    线程与内核对象的同步 --Windows核心编程学习手札之九 用户方式下的线程同步机制具有速度快的特点,但有其局限性,对于许多应用程序来说,并不合适.例如,互锁函数家族只能在单值上运行,根本无法使线程 ...

  8. 线程的调度、优先级和亲缘性——Windows核心编程学习手札系列之七

    线程的调度.优先级和亲缘性 --Windows核心编程学习手札系列之七 每个线程都拥有一个上下文结构,在线程的内核对象中,记录线程上次运行时该线程的CPU寄存器状态.Windows会每隔20ms左右查 ...

  9. 线程基础知识——Windows核心编程学习手札系列之六

    线程基础知识 --Windows核心编程学习手札系列之六 线程与进程一样由两部分构成:一是线程的内核对象,操作系统用它来对线程实施管理,也是系统用来存放线程统计信息的地方:二是线程堆栈,用于维护线程在 ...

最新文章

  1. 6.QT信号槽的时序分析
  2. 长沙网络推广浅析影响网站快照更新时间的因素是什么?
  3. Oracle Golden Gate 系列十五 -- GG Trails 说明
  4. tarjan求强连通分量的思考
  5. Python对文件的三种打开方式以及with管理上下文
  6. boost::posix_time模块实现本地时间和 UTC 之间的转换的测试程序
  7. 事物与持久化_揭开Redis面纱,发布订阅、事务、安全、持久化
  8. gdal 压缩tif_Python | GDAL处理影像
  9. 解决比特币双重支付问题
  10. VIJOS 1512SuperBrother打鼹鼠(二维BIT)
  11. Android音视频开发之-WebRTC技术实践
  12. python下载豆丁文档_doc_downloader
  13. UG与PROE哪个好用,主要看是用在哪里
  14. EYOUCMS常用标签(官方很慢找的一些,持续更新,建议收藏)
  15. android 8 刷机教程视频教程,教你Android 8.0的刷机教程
  16. 【正本清源】算力大战根本就从未开始过!BCH分叉事件之技术细节七问
  17. FPGA图像处理的前景如何?
  18. 浙大计算机学院徐从富段学生,浙江大学计算机科学与技术专业导师介绍:徐从富...
  19. Win11C盘满了怎么清理?Win11清理C盘的方法
  20. Blender图解教程:高仿版超级马里奥(一)帽子建模(附模型下载)

热门文章

  1. C#中获取程序集版本号的方法
  2. 设计模式 经典书籍必备推荐
  3. TypeScript与React中如何使用ref
  4. 【Vue】—子级向父级传递数据
  5. 修改oracle超空间大小,Oracle修改表空间大小详解
  6. HihoCoder-1174拓扑排序
  7. 事业单位的生活是怎么样的?
  8. 什么样的细节会让你觉得一个人的情商高得吓人?
  9. 现在最简单的赚钱套路
  10. 哪个行业既锻炼人又便于今后创业?