TLS简介----转

1. 什么是TLS?
 
TLS是Thread Local Storage(线程局部存储)的简称,是一项解决多线程内部变量使用问题的技术。用于将某些数据和一特定线程关联起来,即,这些数据为关联线程所独有(私有)。在多线程编程中, 同一个变量, 如果要让多个线程共享访问, 那么这个变量可以使用关键字volatile进行声明; 而如果一个变量不想被多个线程共享访问, 那么就应该使用TLS。
 
2. 如何使用TLS编程?
 
TLS使用非常简单, 只要对变量声明时使用__declspec(thread)修饰就可以了。例如:
 

__declspec(thread) int g_nData = 0;

 
3. 一个使用TLS的例子
 

 1 #include<windows.h> 
2 #include<stdio.h>
3
4 #define THREADCOUNT 4
5
6 DWORD dwTlsIndex;
7 int iNUM_OF_CALL_COMMON=0;
8 int iNUM_OF_CALL_THREAD=0;
9
10 VOID ErrorExit(LPSTR);
11
12 VOID CommonFunc(VOID)
13 {
14 LPVOID lpvData;
15 // Retrieve a data pointer for the current thread.
16 iNUM_OF_CALL_COMMON++;
17
18 lpvData = TlsGetValue(dwTlsIndex);
19 if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS))
20 ErrorExit("TlsGetValue error");
21
22 // Use the data stored for the current thread.
23 printf("common: thread %d: lpvData=%lx\n", GetCurrentThreadId(), lpvData);
24 Sleep(5000);
25 }
26
27 DWORD WINAPI ThreadFunc(VOID)
28 {
29 LPVOID lpvData;
30
31 // Initialize the TLS index for this thread.
32 iNUM_OF_CALL_THREAD++;
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 CommonFunc();
39 // Release the dynamic memory before the thread returns.
40 lpvData = TlsGetValue(dwTlsIndex);
41 if (lpvData != 0)
42 LocalFree((HLOCAL) lpvData);
43 return 0;
44 }
45
46 int main(VOID)
47 {
48 DWORD IDThread;
49 HANDLE hThread[THREADCOUNT];
50 int i;
51
52 // Allocate a TLS index.
53 if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
54 ErrorExit("TlsAlloc failed");
55
56 // Create multiple threads.
57 for (i = 0; i < THREADCOUNT; i++)
58 {
59 hThread[i] = CreateThread(NULL, // default security attributes
60 0, // use default stack size
61 (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function
62 NULL, // no thread function argument
63 0, // use default creation flags
64 &IDThread); // returns thread identifier
65
66 // Check the return value for success.
67 if (hThread[i] == NULL)
68 ErrorExit("CreateThread error\n");
69 }
70
71 // printf("All threads were created.\n");
72 for (i = 0; i < THREADCOUNT; i++)
73 WaitForSingleObject(hThread[i], INFINITE);
74
75 TlsFree(dwTlsIndex);
76
77 printf("The nums of thread is: %d\n",iNUM_OF_CALL_THREAD);
78 printf("The nums of call is: %d\n",iNUM_OF_CALL_COMMON);
79
80 return 0;
81 }
82
83 VOID ErrorExit (LPSTR lpszMessage)
84 {
85 fprintf(stderr, "%s\n", lpszMessage);
86 ExitProcess(0);
87 }

 
4. T L S的内部数据结构
 
名称:  1.jpg
查看次数: 484
文件大小:  20.5 KB

图1 用于管理T L S的内部数据结构

 
 
每个标志均可设置为FREE或者INUSE,表示TLS槽( s l o t )是否正在使用。Microsoft保证至少TLS_MINIMUM_AVAILABLE位标志是可供使用的。
 
5. 相关API
 
Windows TLS的API: TlsAlloc, TlsFree, TlsSetValue, TlsGetValue。
 
● DWORD TlsAlloc(); //(若要使用动态T L S,首先必须调用TlsAlloc函数)
 
这个函数命令系统对进程中的位标志进行扫描,并找出一个FREE标志。然后系统将该标志从FREE改为INUSE,并且TlsAlloc返回位数组中的标志的索引。DLL(或APP)通常将该索引保存在一个全局变量中,因为它的值是每个进程而不是每个线程使用的值。
 
● BOOL TlsSetValue( //将一个值放入线程的数组中
 
DWORD dwTlsIndex,
 
PVOID pvTlsValue);
 
● PVOID TlsGetValue(DWORD dwTlsIndex); //要从线程的数组中检索一个值
 
● BOOL TlsFree(DWORD dwTlsIndex); //当在所有线程中不再需要保留TLS槽时
 
参考资料:Jeffrey Richter《《Programming Applications for Microsoft Windows (4th Ed.)》》Chapter 21
 
6. TLS目录
 
名称:  7.JPG
查看次数: 485
文件大小:  82.7 KB
TLS Callback Functions
这是线程建立和退出时的回调函数, 包括主线程和其他线程.AddressOfCallBacks 是指向函数指针数组的指针, 以 0 结束. 
 
 typedef struct _TEB {
NT_TIB Tib;
PVOID EnvironmentPointer;
CLIENT_ID Cid;
PVOID ActiveRpcInfo;
PVOID ThreadLocalStoragePointer; ; 2ch
PPEB Peb; ; 30h
ULONG LastErrorValue; ; 34h
…}
 
TLS目录 #define IMAGE_DIRECTORY_ENTRY_TLS 9 (第十个目录)

posted on 2012-02-17 08:17  梦想Sky  阅读(1565)  评论(0编辑  收藏  举报

导航