线程局部存储技术
TLSAlloc 功能:在本进程 中的 线程本地存储区的位标示数组中 找到一个是否可以用的。
如果找到,则去该标示位 对应着的 的线程数组中找索引,如果找到,则返回索引。
我发一个图给大家看。
问题:TlSAlloc是进程分配的, 我提供的代码是在主线程中使用,
4个线程用到了dwTlsIndex,dwTlsIndex 的值是一样的。
4个线程,应该是在主线程中调用四次Tlsalloc,进行分配到4个,然后
4个线程各自使用自己的。
tlsalloc 是查找标志位,然后再标志位对应的数组中查找。
即:返回我提供的图中的 竖着的数组的索引,不是返回横着的那个数组的
索引。
难道我理解错了吗??
- C/C++ code
#include <windows.h>#include <stdio.h>#define THREADCOUNT 4DWORD dwTlsIndex;VOID ErrorExit(LPSTR); DWORD WINAPI ThreadFunc(VOID){ LPVOID lpvData; // Initialize the TLS index for this thread. lpvData = (LPVOID) LocalAlloc(LPTR, 256); if (! TlsSetValue(dwTlsIndex, lpvData)) ErrorExit("TlsSetValue error"); printf("thread %d: lpvData=%lx\n", GetCurrentThreadId(), lpvData); // CommonFunc(); // Release the dynamic memory before the thread returns. lpvData = TlsGetValue(dwTlsIndex); if (lpvData != 0) LocalFree((HLOCAL) lpvData); return 0;} int main(VOID){ DWORD IDThread; HANDLE hThread[THREADCOUNT]; int i; // Allocate a TLS index. if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) ErrorExit("TlsAlloc failed"); // Create multiple threads. for (i = 0; i < THREADCOUNT; i++) { hThread[i] = CreateThread(NULL, // default security attributes 0, // use default stack size (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function NULL, // no thread function argument 0 , // use default creation flags &IDThread); // returns thread identifier // Check the return value for success. if (hThread[i] == NULL) ErrorExit("CreateThread error\n"); } for (i = 0; i < THREADCOUNT; i++) WaitForSingleObject(hThread[i], INFINITE); TlsFree(dwTlsIndex); return 0;}VOID ErrorExit (LPSTR lpszMessage){ fprintf(stderr, "%s\n", lpszMessage); ExitProcess(0);}
[解决办法]
Win32 方法一:每个线程创建时系统给它分配一个LPVOID指针的数组(叫做TLS数组),这个数组从C编程角度是隐藏着的不能直接访问,需要通过一些C API函数调用访问。首先定义一些DWORD线程全局变量或函数静态变量,准备作为各个线程访问自己的TLS数组的索引变量。一个线程使用TLS时,第一步在线程内调用TlsAlloc()函数,为一个TLS数组索引变量与这个线程的TLS数组的某个槽(slot)关联起来,例如获得一个索引变量: global_dwTLSindex=TLSAlloc(); 注意,此步之后,当前线程实际上访问的是这个TLS数组索引变量的线程内的拷贝版本。也就说,不同线程虽然看起来用的是同名的TLS数组索引变量,但实际上各个线程得到的可能是不同DWORD值。其意义在于,每个使用TLS的线程获得了一个DWORD类型的线程局部静态变量作为TLS数组的索引变量。C/C++原本没有直接定义线程局部静态变量的机制,所以在如此大费周折。 第二步,为当前线程动态分配一块内存区域(使用LocalAlloc()函数调用),然后把指向这块内存区域的指针放入TLS数组相应的槽中(使用TlsValue()函数调用)。 第三步,在当前线程的任何函数内,都可以通过TLS数组的索引变量,使用TlsGetValue()函数得到上一步的那块内存区域的指针,然后就可以进行内存区域的读写操作了。这就实现了在一个线程内部这个范围处处可访问的变量。 最后,如果不再需要上述线程局部静态变量,要动态释放掉这块内存区域(使用LocalFree()函数),然后从TLS数组中放弃对应的槽(使用TlsFree()函数)。
[解决办法]