使用线程局部存储TLS
来源:互联网 发布:淘宝5xl的裤子是多少码 编辑:程序博客网 时间:2024/04/27 21:53
Thread local storage(TLS)统一进程的多个线程可以通过由TlsAlloc方法返回的索引值在线程自身的空间内存储和取回一个值。在以下这个例子里,索引值在进程开始时创建,当各个线程启动时,会各自申请一块动态内存并且将内存指针通过TlsSetValue方法存储到各自的TLS空间中(由先前的索引值标定)。CommonFunc方法使用TlsGetValue方法通过索引取得数据指针。在各个线程结束前,释放动态内存块。在进程结束见,调用TlsFree方法释放索引。
2#include <stdio.h>
3
4#define THREADCOUNT 4
5DWORD dwTlsIndex;
6
7VOID ErrorExit(LPSTR);
8
9VOID CommonFunc(VOID)
10{
11 LPVOID lpvData;
12
13// Retrieve a data pointer for the current thread.
14
15 lpvData = TlsGetValue(dwTlsIndex);
16 if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS))
17 ErrorExit("TlsGetValue error");
18
19// Use the data stored for the current thread.
20
21 printf("common: thread %d: lpvData=%lx/n",
22 GetCurrentThreadId(), lpvData);
23
24 Sleep(5000);
25}
26
27DWORD WINAPI ThreadFunc(VOID)
28{
29 LPVOID lpvData;
30
31// Initialize the TLS index for this thread.
32
33 lpvData = (LPVOID) LocalAlloc(LPTR, 256);
34 if (! TlsSetValue(dwTlsIndex, lpvData))
35 ErrorExit("TlsSetValue error");
36
37 printf("thread %d: lpvData=%lx/n", GetCurrentThreadId(), lpvData);
38
39 CommonFunc();
40
41// Release the dynamic memory before the thread returns.
42
43 lpvData = TlsGetValue(dwTlsIndex);
44 if (lpvData != 0)
45 LocalFree((HLOCAL) lpvData);
46
47 return 0;
48}
49
50int main(VOID)
51{
52 DWORD IDThread;
53 HANDLE hThread[THREADCOUNT];
54 int i;
55
56// Allocate a TLS index.
57
58 if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
59 ErrorExit("TlsAlloc failed");
60
61// Create multiple threads.
62
63 for (i = 0; i < THREADCOUNT; i++)
64 {
65 hThread[i] = CreateThread(NULL, // default security attributes
66 0, // use default stack size
67 (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function
68 NULL, // no thread function argument
69 0, // use default creation flags
70 &IDThread); // returns thread identifier
71
72 // Check the return value for success.
73 if (hThread[i] == NULL)
74 ErrorExit("CreateThread error/n");
75 }
76
77 for (i = 0; i < THREADCOUNT; i++)
78 WaitForSingleObject(hThread[i], INFINITE);
79
80 TlsFree(dwTlsIndex);
81
82 return 0;
83}
84
85VOID ErrorExit (LPSTR lpszMessage)
86{
87 fprintf(stderr, "%s/n", lpszMessage);
88 ExitProcess(0);
89}
90
常用情景:
各个线程所处理的对象有所不同,但是所需要的处理却可能类似,例如多个线程同时处理多个文件,就可以将文件句柄存在在相应的Tls中,在使用相同的接口进行处理
背景知识:
每个线程除了共享进程的资源外还拥有各自的私有资源:一个寄存器组(或者说是线程上下文);一个专属的堆栈;一个专属的消息队列;一个专属的Thread Local Storage(TLS);一个专属的结构化异常处理串链。
TLS 是一个良好的Win32 特质,让多线程程序设计更容易一些。TLS是一个机制,经由它,程序可以拥有全域变量,但在不同的线程里有不同的值。也就是说,进程中的所有线程都可以拥有全域变量,但这些变量其实是特定对某个线程才有意义。例如,你可能有一个多线程程序,每一个线程都对不同的文件写文件(也因此它们使用不同的文件handle)。这种情况下,把每一个线程所使用的文件handle 储存在TLS 中,将会十分方便。当线程需要知道所使用的handle,它可以从TLS获得。重点在于:线程用来取得文件handle 的那一段码在任何情况下都是相同的,而从TLS中取出的文件handle却各不相同。非常灵巧,不是吗?有全域变数的便利,却又分属各线程。
虽然TLS 很方便,它并不是毫无限制。在Windows NT 和Windows 95 之中,有64 个DWORD slots供每一个线程使用。这意思是一个进程最多可以有64 个「对各线程有不同意义」的DWORDs。 虽然TLS可以存放单一数值如文件handle,更常的用途是放置指针,指向线程的私有资料。有许多情况,多线程程序需要储存一堆数据,而它们又都是与各线程相关。许多程序员对此的作法是把这些变量包装为C 结构,然后把结构指针储存在TLS中。当新的线程诞生,程序就配置一些内存给该结构使用,并且把指针储存在为线程保留下来的TLS中。一旦线程结束,程序代码就释放所有配置来的区块。既然每一个线程都有64 个slots用来储存线程自己的数据,那么这些空间到底打哪儿来?在线程的学习中我们可以从结构TDB中看到,每一个thread database 都有64个DWORDs 给TLS 使用。当你以TLS 函式设定或取出数据,事实上你真正面对的就是那64DWORDs。好,现在我们知道了原来那些“对各线程有不同意义的全局变量”是存放在线程各自的TDB中阿。
接下来你也许会问:我怎么存取这64个DWORDS呢?我又怎么知道哪个DWORDS被占用了,哪个没有被占用呢?首先我们要理解这样一个事实:系统之所以给我们提供TLS这一功能,就是为了方便的实现“对各线程有不同意义的全局变量”这一功能;既然要达到“全局变量”的效果,那么也就是说每个线程都要用到这个变量,既然这样那么我们就不需要对每个线程的那64个DWORDS的占用情况分别标记了,因为那64个DWORDS中的某一个一旦占用,是所有线程的那个DWORD都被占用了,于是KERNEL32使用两个DWORDs(总共64 个位)来记录哪一个slot 是可用的、哪一个slot 已经被用。这两个DWORDs 可想象成为一个64位数组,如果某个位设立,就表示它对应的TLS slot 已被使用。这64 位TLS slot 数组存放在process database中(在进程一节中的PDB结构中我们列出了那两个DWORDs)。
下面的四个函数就是对TLS进行操作的:
(1)TlsAlloc
上面我们说过了KERNEL32 使用两个DWORDs(总共64 个位)来记录哪一个slot 是可用的、哪一个slot 已经被用。当你需要使用一个TLS slot 的时候,你就可以用这个函数将相应的TLS slot位置1。
(2)TlsSetValue
TlsSetValue 可以把数据放入先前配置到的TLS slot 中。两个参数分别是TLS slot索引值以及欲写入的数据内容。TlsSetValue 就把你指定的数据放入64 DWORDs 所组成的数组(位于目前的threaddatabase)的适当位置中。
(3)TlsGetValue
这个函数几乎是TlsSetValue 的一面镜子,最大的差异是它取出数据而非设定数据。和TlsSetValue一样,这个函数也是先检查TLS 索引值合法与否。如果是,TlsGetValue 就使用这个索引值找到64 DWORDs 数组(位于threaddatabase 中)的对应数据项,并将其内容传回。
(4)TlsFree
这个函数将TlsAlloc 和TlsSetValue 的努力全部抹消掉。TlsFree先检验你交给它的索引值是否的确被配置过。如果是,它将对应的64 位TLS slots位关闭。然后,为了避免那个已经不再合法的内容被使用,TlsFree 巡访进程中的每一个线程,把0 放到刚刚被释放的那个TLS slot上头。于是呢,如果有某个TLS 索引后来又被重新配置,所有用到该索引的线程就保证会取回一个0 值,除非它们再调用TlsSetValue。
- 使用线程局部存储TLS
- 使用线程局部存储TLS
- 线程局部存储TLS
- 线程局部存储TLS
- TLS--线程局部存储
- 线程局部存储(TLS)
- 线程局部存储(TLS)
- TLS--线程局部存储
- 线程局部存储TLS
- TLS--线程局部存储
- TLS--线程局部存储
- TLS--线程局部存储
- TLS--线程局部存储
- TLS---线程局部存储
- 线程局部存储TLS
- TLS线程局部存储
- 线程局部存储TLS
- TLS--线程局部存储
- 创建web dynpro的trascation code
- 几种获取IP地址的协议
- 32位cpu寻址小结(转载)
- LR动态链接数据库
- sql server日期时间转字符串(懒得记)
- 使用线程局部存储TLS
- 使用javascript过滤字符串前后的空格
- jvm参数设置
- 清除SVN目录
- Installed JREs for Eclipse
- Hibernate批量更新和批量删除
- Gigahttpd 改名成 Gigah 了
- SQL使用链接服务器执行远程数据库上的存储过程
- sqlhelp.cs