Windows Internals 笔记——线程局部存储区
1.由于C/C++运行库是在多线程应用程序出现的许多年前设计的,因此运行库中的大多数函数是为单线程应用程序设计的。
2.当应用程序第一次调用_tcstok_s的时候该函数将传入的字符串地址保存在它自己的静态变量中,当我们后来再传入NULL的时候,该函数会去引用保存下来的字符串地址。多线程情况下一个线程可能会覆盖另一个线程的静态变量,为了解决这个问题,C/C++ 运行库使用了TLS。
int main()
{
char strToken[] = "A BC,DE\\FGH";
const char strDelimit[] = " ,\\"; char *context = nullptr;
char *next_context = nullptr; context = strtok_s(strToken, strDelimit, &next_context); while (context != nullptr)
{
std::cout << context << std::endl;
context = strtok_s(nullptr, strDelimit, &next_context);
} getchar();
return ;
}
3.系统中的每个进程都有一组正在使用标志,每个标志可以被设为FREE或INUSE,表示该TLS元素是否正在使用。Microsoft保证至少有TLS_MINIMUN_AVAILABLE个标志可供使用。再WinNT.h中被定义为64,系统在需要的时候分配更多的TLS元素,最多可达1000多个!
动态TLS
1.DWORD TlsAlloc(); 这个函数让系统对进程中的位标志进行检索并找到一个FREE标志。然后系统会将该标志从FREE改为INUSE并返回该标志在数组中的索引,并且这个索引无论是进程中当前正在运行的线程,还是今后可能会创建的线程都不能再使用。TlsAlloc在返回之前,会遍历进程中的每个线程,并根据新分配的索引,在每个线程的数组中把对应的元素设为0。如果没有,则返回TLS_OUT_OF_INDEXES(0xFFFFFFFF)。
2.当系统创建一个线程的时候,会分配TLS_MINIMUM_AVAILABLE个PVOID值,将它们都初始化为0,并与线程关联起来,每个线程都有自己的PVOID数组,数组中的每个PVOID可以保存任意值。
3.BOOL TlsSetValue(DWORD dwTlsIndex, PVOID pvTlsValue); 把一个值放到线程的数组中,但是它无法修改另一个线程的TLS值。为了使得函数运行得尽可能快,牺牲了错误检查,即使传入得索引值不是由TlsAlloc分配得到的。
4.PVOID TlsGetValue(DWORD dwTlsIndex);只会查看属于调用线程得数组。
5.BOOL TlsFree(DWORD dwTlsIndex); 函数会将进程内的标志位数组中对应的INUSE标志重新设回FREE,还会将所有线程中该元素的内容设为0。
6.通常,如果DLL要使用TLS,会在DLL_PROCESS_ATTACH的时候调用TlsAlloc,在DLL_PROCESS_DETACH的时候调用TlsFree。
静态TLS
__declspec(thread) DWORD gt_dwStartTime;
1. __declspec(thread) 告诉编译器应该在可执行文件或DLL文件中,把对应的变量放到它自己的段中。__declspec(thread)后面的变量必须被声明为全局变量或静态变量。
2.当编译器对程序进行编译的时候,会将所有TLS变量放到它们自己的段中,这个段名为.tls。链接岂会将所有对象模块中的.tls段合并成一个大的.tls段,并将它保存到生成的可执行文件或DLL文件中。
3.当系统将应用程序载入到内存的时候,会查看可执行文件中的.tls段,并分配一块足够大的内存来保存所有的静态TLS变量。每当应用程序中的代码引用到这些变量之一时,相应的引用会被解析到刚分配的这块内存中的一个位置。
4.如果进程创建了另一个线程,那么系统会获知这一情况并自动分配另一块内存来保存新线程的静态TLS变量,新线程只能访问自己的静态TLS变量。
5.当系统载入应用程序的时候,会首先确定应用程序的.tls段的大小,并将它与应用程序链接的所有DLL的.tls段的大小相加。当系统在创建线程的时候,会自动分配一块足够大的内存来保存应用程序和所有隐式链接的DLL需要的TLS变量。
Windows Internals 笔记——线程局部存储区的更多相关文章
- Windows Internals 笔记——线程
1.进程有两个组成部分,一个进程内核对象和一个地址空间.线程也有两个组成部分: 一个是线程的内核对象,操作系统用它管理线程.系统还用内核对象来存放线程统计信息的地方. 一个线程栈,用于维护线程执行时所 ...
- Windows Internals 笔记——线程优先级
1.每个线程都被赋予0(最低)~31(最高)的优先级数.当系统确定给哪个线程分配CPU时,它会首先查看优先级为31的线程,并以循环的方式进行调度.如果有优先级为31的线程可供调度,那么系统就会将CPU ...
- Windows Internals 笔记——关联性
1.默认情况下,Windows Vista在给线程分配处理器时,使用软关联.意思是如果其他因素都一样,系统将使线程在上一次运行的处理器上运行.让线程始终在同一个处理器上运行有助于重用仍在处理器高速缓存 ...
- Windows Internals 笔记——错误处理
1.Windows函数检测到错误时,会使用一种名为“线程本地存储区”的机制将相应的错误代码与“主调线程”关联到一起.这种机制使得不同的线程能独立运行,不会出现相互干扰对方的错误代码的情况. 2.Get ...
- Windows Internals 笔记——线程调度
1.线程内核对象中的CONTEXT反应了线程上一次执行时CPU寄存器的状态.大约每隔20ms,Windows都会查看所有当前存在的线程内核对象.Windows在可调度的线程内核对象中选择一个,并将上次 ...
- Windows Internals 笔记——CreateProcess
1.一个线程调用CreateProcess时,系统将创建一个进程内核对象,其初始使用计数为1.然后系统为新进程的主线程创建一个线程内核对象(使其计数为1). 2.CreateProcess在进程完全初 ...
- Windows Internals 笔记——进程
1.一般将进程定义成一个正在运行的程序的一个实例,由以下两部分构成: 一个内核对象,操作系统用它来管理进程,内核对象也是系统保存进程统计信息的地方. 一个地址空间,其中包含所有可执行文件或DLL模块的 ...
- Windows Internals 笔记——进程的权限
1.大多数用户都用一个管理员账户来登录Windows,在Vista之前,这样的登录会创建一个安全令牌.每当有代码试图使用一个受保护的安全资源时,操作系统就会出示这个令牌.从包括Windows资源管理器 ...
- Windows Internals 笔记——作业
1.Windows提供了一个作业内核对象,它允许我们将进程组合在一起并创建一个“沙箱”来限制进程能够做什么.创建只包含一个进程的作业同样非常有用,因为这样可以对进程施加平时不能施加的限制. 2.如果进 ...
随机推荐
- 域scope 介绍,及查找数据
书中介绍<jsp:useBean> 中属性 scope: <%@ page language="java" pageEncoding="UTF-8& ...
- openstack Q版部署-----nova服务配置-控制节点(5)
一.创建数据库(控制节点) 创建数据库以及用户: CREATE DATABASE nova_api; CREATE DATABASE nova; CREATE DATABASE nova_cell0; ...
- [Harbor]Docker登录Harbor仓库(HTTP方式)
Docker登录到Harbor仓库时,不管是使用http协议还是使用https协议,都需要修改一些配置. 这篇文章来介绍一下,在使用http协议时,需要进行什么哪些配置. 首先,确定自己的Harbor ...
- 【转】python f-string
[转]python f-string 文章目录 1. 主要内容 1.1. 旧时代的格式化字符串 1.1.1. Option #1: %-formatting 1.1.2. 怎样使用 %-forma ...
- Linux中设置别名
作者:邓聪聪 查看别名: alias设置别名: 临时设置: alias show='ls -al' 永久生效: 修改 家目录/.bashrc [root@localhost ~]# cat .bash ...
- Java常见异常及解释
- shutil.copy()、os.walk()、os.rename()实例
#!/usr/bin/python # -*- coding: UTF-8 -*- import os import shutil Path = "panel/" PNPath = ...
- Control算法相关
Control算法相关 添加新的control算法官方指导教程. 创建一个控制器: 在文件control_config中添加新控制器的配置信息: 注册新控制器. 如何添加新的CAN卡. Apollo中 ...
- (常用)configparser,hashlib,hamc模块
configparser模块 #专门解析my.ini这种形式的文件(cnf) import configparser config=configparser.ConfigParser() conf ...
- [HTTP]HTTP 中的 Transfer-Encoding 报文头
一.背景: 持续连接的问题:对于非持续连接,浏览器可以通过连接是否关闭来界定请求或响应实体的边界:而对于持续连接,这种方法显然不奏效.有时,尽管我已经发送完所有数据,但浏览器并不知道这一点,它无法得知 ...