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.如果进 ...
随机推荐
- ASP.NET MVC - 处理Html数据
HtmlAgilityPack 使用HtmlAgilityPack可以以面向对象的方式通过查找Html节点来获取页面元素.参考:http://html-agility-pack.net HtmlDoc ...
- 51nod 1232 完美数
题目思路:数位dp,若这个数能被每位的非0数整除,那么这个数一定可以被每一位数的lcm整除,lcm(1,2,3,4,5,6,7,8,9) = 2520,所以可以通过将这个数对2520取模来压缩空间,取 ...
- Palindromic Numbers LightOJ - 1205
题目大意: 求区间内的回文数个数 题目思路: 数位dp,先枚举前一半数字,然后填上相应的后一半数字. #include<cstdio> #include<cstring> #i ...
- linux系统 户和账号操作
1,基本操作要求 实现用户账号的管理,要完成的工作主要有如下几个方面: · 用户账号的添加.删除与修改.· 用户口令的管理.· 用户组的管理. 2,用户账户添加删除 ...
- Nginx系列4:用GoAccess实现可视化并实时监控access日志
1.ubuntu16.04安装GoAccess GoAccess下载地址:https://goaccess.io/download 安装步骤: $ wget https://tar.goaccess. ...
- BurpSuite使用笔记
参考:Burp Suite 实战指南 Proxy模块 options--> add 设置监听地址,端口 binding 如果是作为本地浏览器代理默认(127.0.0.1:8080)就可以了. 如 ...
- [Docker]CentOS7下Docker安装教程
想要倒腾Kubernetes的话,第一步就是要会安装Docker,这篇文章讲一讲过程 安装步骤 检查内核版本,必须是3.10以上 uname -r 安装Docker yum -y install do ...
- 狼抓兔子 BZOJ- 1001 最小割
https://www.lydsy.com/JudgeOnline/problem.php?id=1001 一个图,问你花费多少才能把到终点的所有边堵住... 就是求一个最小割,把$(1,1)$和$( ...
- where(泛型类型约束)
.NET支持的类型参数约束有以下五种: where T : struct T必须是一个结构类型 where T : class T必须是一个类(class)类型,不能是结构(structure)类型 ...
- 清理messages提示-bash: /var/log/messages: Operation not permitted的处理
报警提示系统盘容量不足了/var/log下查看messages日志已经很大了,所以就想着把messages清空一下,以此来释放空间.在删除的时候提示没有权限. 看了下日志,发现是大量的haproxy日 ...