线程局部存储区

来源:互联网 发布:取消电视软件自动升级 编辑:程序博客网 时间:2024/05/03 23:18

尽量少使用全局变量和静态变量,尽量用栈上变量,也可用动态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 不要用多个索引存放一个数组,不如一个索引存放一个数组指针。

 

0 0