线程局部存储区
盡量少使用全局變量和靜態變量,盡量用棧上變量,也可用動態TLS和靜態TLS
數據與對象實例關聯起來
如SetWindowWord / SetWindowLong 將數據與窗口關聯起來
進程中每個線程都有TLS_MINIMUM_AVAILABLE個PVOID值的數組,一旦一個線程預訂了一個索引,進程內所有正在運行或將創建的線程都不能再使用這個索引
DWORD TlsAlloc();
TlsSetValue
TlsGetValue
TlsFree(DWORD index);
對DLL使用TLS,TlsAlloc放在DLL_PROCESS_ATTACH,TlsFree放在DLL_PROCESS_DETACH。 而index作為全局變量,但index不能其他用處會涉及多線程問題。
// dll project
// testdll.h
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
#include <Windows.h>
typedef struct _SomeStruct{
?DWORD index;
?DWORD tid;
?char buf[256];
}SomeStruct,*PSomeStruct;
TESTDLL_API PSomeStruct Fun(PSomeStruct pSomeStruct);
//testdll.cpp
#include "testdll.h"
#include <iostream>
#include <Windows.h>
DWORD g_dwTlsIndex;
BOOL APIENTRY DllMain( HMODULE hModule,
?????????????????????? DWORD? ul_reason_for_call,
?????????????????????? LPVOID lpReserved
????? )
{
?switch (ul_reason_for_call)
?{
?case DLL_PROCESS_ATTACH:
??{
???g_dwTlsIndex = TlsAlloc();
???std::cout << "case DLL_PROCESS_ATTACH: TlsAlloc:" << g_dwTlsIndex << std::endl;
??}
??break;
?case DLL_THREAD_ATTACH:
??break;
?case DLL_THREAD_DETACH:
??break;
?case DLL_PROCESS_DETACH:
??{
???TlsFree(g_dwTlsIndex);
???std::cout << "case DLL_PROCESS_DETACH: TlsFree:" << g_dwTlsIndex << std::endl;
??}
??break;
?}
?return TRUE;
}
TESTDLL_API PSomeStruct Fun(PSomeStruct pSomeStruct)
{
?if( pSomeStruct != NULL )
?{
??pSomeStruct->index = g_dwTlsIndex;
??if( TlsGetValue(g_dwTlsIndex) == NULL )
??{
???TlsSetValue(g_dwTlsIndex,HeapAlloc(GetProcessHeap(),0,sizeof(*pSomeStruct)));
??}
??memcpy(TlsGetValue(g_dwTlsIndex),pSomeStruct,sizeof(*pSomeStruct));
??return NULL;
?}
?else
?{
??return (PSomeStruct)TlsGetValue(g_dwTlsIndex);
?}
}
?
//test project
//main.cpp
#include <Windows.h>
#include "testdll\testdll.h"
#include <iostream>
#include <process.h>
unsigned __stdcall SecondThreadFunc( void* pArguments )
{
?DWORD tid = GetCurrentThreadId();
?SomeStruct ss = {0,tid,""};
?memcpy(ss.buf,pArguments,strlen((const char*)pArguments));
?
?Fun(&ss);
?while(true)
?{
??PSomeStruct pget =Fun(NULL);
??std::cout << "tlsindex:" << pget->index << "? tid:" << tid << "? buf:" << pget->buf << std::endl;
??Sleep(2000);
?}
?_endthreadex( 0 );
??? return 0;
}
int wmain(int argc, wchar_t* argv[])
{
?DWORD tid = GetCurrentThreadId();
?SomeStruct ss = {0,tid,"11111111"};
?Fun(&ss);
?PSomeStruct pget =Fun(NULL);
?std::cout << "tlsindex:" << pget->index << "? tid:" << tid << "? buf:" << pget->buf << std::endl;
?
?HANDLE hThread1,hThread2;
??? unsigned threadID;
?char *str1 = "first thread value";
?char *str2 = "second thread value";
?hThread1 = (HANDLE)_beginthreadex( NULL, 0, SecondThreadFunc, str1, 0, &threadID );
?hThread2 = (HANDLE)_beginthreadex( NULL, 0, SecondThreadFunc, str2, 0, &threadID );
?WaitForSingleObject( hThread1, INFINITE );
?WaitForSingleObject( hThread2, INFINITE );
?CloseHandle( hThread1 );
?CloseHandle( hThread2 );
?return 0;
}
?
//test result:
?
note: TLS 不要用多個索引存放一個數組,不如一個索引存放一個數組指針。
?
總結
- 上一篇: DLL 延时加载
- 下一篇: 方式四:修改模块导入段来拦截API