TLS--线程局部存储

 

转自:https://blog.csdn.net/u013761036/article/details/54960277

这个东西并不陌生了,之前写过了一个关于这个的应用,利用静态TLS姿势实现代码段静态加密免杀或者所谓的加壳思路。地址在这:http://blog.csdn.net/u013761036/article/details/53967943今天就简单的整理下TLS的相关概念和常规应用。一开始说了一大堆的Windows的进程与线程啥啥啥的概念和原理,这里直接省略。

什么是线程局部存储?

    线程局部存储(Thread Local Storage,TLS)很好的解决了多线程设计中变量同步问题,比如你写一个exe里面有N个线程,你可以放弃使用TLS,因为你对自己设计的程序有比较全面的把握。你清楚自己设计的进程里总共有多少个线程,每个线程使用了哪些数据结构,内存空间申请、释放都在你的掌控之下,全局变量的访问全部都采用了同步技术,那是没问题的。如果你是一个DLL开发者,你无法确定调用这个DLL的素质程序里到底有多少个线程,每个线程的数据是如何定义的,这时,可以考虑使用线程据存储技术。

 

TLS分为静态和动态两种:

动态TLS,主要是使用这几个API TlsAlloc ,TlsGetValue,TlsSetValue,TlsFree

下面是微软MSDN上的一个例子,看下理解下:

 

 

[cpp] view plain copy

  1. #include    
  2. #include    
  3.    
  4. #define THREADCOUNT 4   
  5. DWORD dwTlsIndex;   
  6.    
  7. VOID ErrorExit(LPSTR);   
  8.    
  9. VOID 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.    
  27. DWORD 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.    
  50. int 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.    
  85. VOID ErrorExit (LPSTR lpszMessage)   
  86. {   
  87.    fprintf(stderr, "%s\n", lpszMessage);   
  88.    ExitProcess(0);   
  89. }  


 

 

 

静态TLS

    静态线程局部存储是操作系统提供的另外一种线程与数据绑定的技术。它与动态TLS的区别在于,通过静态线程局部存储指定的数据无需使用专门的API函数,随意在易用性上会更好一些。

    静态线程局部存储预先将变量定义在PE文件内部,一般使用.tls节存储,对于相关API的调用由操作系统来完成。这种方式的有点就是从高级语言程序员角度来看更简单了。这种实现方式使得TLS数据的定义与初始化就像程序中使用普通的静态变量那样。

    对静态TLS变量的定义不需要想动态线程局部存储一样,调用相关API,只需要做如下声明即可:

_declspec(thread) int tlsFlag=1;

     为了支持这种编程模式。PE中的.tls节会包含一下信息:

初始化数据

用于每个线程初始化和终止的回调函数

TLS索引

你可能感兴趣的:(C++技术类)