21.1 动态TLS--《Windows核心编程》

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

通常情况下,如果DLL使用 TLS,那么当它用 DLL_PROCESS_ATTACH 标志调用它的 DllMain 函数时,它也调用TlsAlloc。当它用DLL_PROCESS_DETACH 调用 DllMain 函数时,它就调用 TlsFree。对 TlsSetValue 和 TlsGetValue 的调用很可能是在调用DLL中包含的函数时进行的。


动态TLS的使用

头文件:Windows.h
使用到的函数:TlsAlloc,TlsSetValue,TlsGetValue,TlsFree

 

(1)DWORD TlsAlloc();

作用:为调用该函数的线程分配一个线程局部存储序号,供其它三个函数使用
注意:一个进程最多分配TLS_MINIMUM_AVAILABLE个索引,目前定义为64,一个进程中所有线程分配的索引不会重复

int index=TlsAlloc()


(2)BOOL TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue);

作用:在指定的序号内存储数据,如TlsAlloc分配成功返回的序号

BOOL ret=TlsSetValue(index,(LPVOID)0x123456)


(3)LPVOID TlsGetValue(DWORD dwTlsIndex);

作用:取得指定序号内存储的数据

LPVOID lp=TlsGetValue(index);


(4)BOOL TlsFree(DWORD dwTlsIndex);

作用:释放指定序号

TlsFree(index);

 

#include<iostream>
#include<Windows.h>
using namespace std;
LPVOID fun(int ind) {
	return TlsGetValue(ind);
}

DWORD WINAPI testThr(LPVOID lpThreadParameter) {
	int ind = (int)lpThreadParameter;
	cout << "另启线程调用fun函数获取:" << fun(ind) << endl;
	return 0;
}

int main() {
	DWORD index = TlsAlloc();					// 分配一个TLS索引
	BOOL ret = TlsSetValue(index, (LPVOID)0x123456);		// 设置该索引的值为0x123456
	LPVOID p = TlsGetValue(index);				// 根据该索引获取该值
	cout << "主线程Main函数中:" << p << endl;	// 输出该值
	cout << "主线程调用fun函数:" << fun(index) << endl;	// 调用fun函数获取该值
	HANDLE hThr = CreateThread(NULL, 0, testThr, (LPVOID)index, NULL, NULL);	// 创建一个新线程,传入索引
	WaitForSingleObject(hThr, 5000);			// 等待新建线程结束
	TlsFree(index);								// 释放该索引

	// 进程和子线程很明显输出不一样
}

 


 

动态TLS原理

  

windows系统中每个进程都有一组正在使用标志(in-use-flag),如图21-1所示。每个标志可以被设为FREE或着INUSE,表示改TLS元素是否正在被使用。Microsoft保证至少有TLS_MINIMUM_AVAILABLE = 64个位标志可供使用。在必要的时候可以配更多,最多可达1000多个。而每一个线程拥有一个自己独立的TLS slot数组,用于存储TLS数据。

动态TLS的使用相对静态TLS稍微麻烦一点,但是无论是将其用在可执行文件中还是DLL中,都还是很简单的。而且当用在DLL中时,没有由于DLL链接方式而可能产生的问题,所以,如果要在DLL中用TLS,又不能保证客户始终采用隐式链接方式,那么请采用动态TLS的实现。

 

posted @ 2022-11-23 11:43  人类观察者  阅读(124)  评论(0编辑  收藏  举报