天天看點

線程局部存儲(TLS)

線程局部存儲區(Thread Local Storage, TLS):将資料與一個正在執行的特定函數關聯起來。

線程局部存儲是将現有函數變為線程安全的有用技巧。

當一個函數中通路并修改全局或靜态變量,那麼這個函數就是不可重入的。若使之變為可重入的函數,可以使用線程同步,也可以使用線程局部存儲。線程局部存儲為每一個通路此變量的線程提供一個此變量獨立的副本,線程可以修改此變量,而不會影響到其他線程。

注:通過以上描述可以看出,線程局部存儲不是用來共享變量的。

C标準庫中的strtok就是一個典型的不可重入函數。當程式第一次調用它時,該函數會将傳入的字元串位址儲存在它自己的靜态變量中;當再次調用strtok并傳入NULL時,該函數會自動引用儲存下來的字元串位址。

想一想,如果一個線程正在使用strtok的時候,另外一個線程也調用此函數,那就會産生很大的問題,第一個線程傳入的字元串被替換掉了!為了解決這種問題,C/C++運作庫使用了TLS。

Windows中應用TLS的一個簡單示例:計算線程的運作時間

  1 //

 2  #include <windows.h>

 3 #include <process.h>

 4 

 5 #include <ctime>

 6 #include <cstdlib>

 7 #include <vector>

 8 #include <iostream>

 9 

10  using  namespace std;

11 

12 unsigned  int __stdcall threadProc( void *arg)

13 {

14     DWORD tlsIndex = reinterpret_cast<DWORD>(arg);

15     clock_t begin = clock();

16     TlsSetValue(tlsIndex, PVOID(begin) );   //  利用TlsSetValue 設定 值

17 

18     printf( " \nbegin thread: %d, clock_t: %d ", GetCurrentThreadId() , begin);

19 

20     Sleep( 3000);

21 

22     clock_t end = clock();

23     clock_t diff = end -  reinterpret_cast<clock_t>(TlsGetValue(tlsIndex) );

24      double sec =  1.0 * diff / CLOCKS_PER_SEC;  //  利用TlsGetValue取得值

25 

26     printf( " \nend thread: %d, clock: %d, live time %f ", GetCurrentThreadId(), end, sec );

27 

28      return  0;

29 }

30 

31  int main( int argc,  char *argv[])

32 {

33      //  配置設定Tls索引

34      DWORD tlsIndex = TlsAlloc();

35 

36     vector<HANDLE> threads;

37      for ( int i =  0; i <  50; ++i){

38         HANDLE h = (HANDLE)_beginthreadex(NULL,  0, threadProc, ( void*)tlsIndex,  0, NULL);

39         threads.push_back(h);

40     }

41 

42      for (size_t i =  0; i < threads.size(); ++i){

43         WaitForSingleObject(threads[i], INFINITE);

44         CloseHandle(threads[i]);

45     }

46 }

47  //

轉載于:https://www.cnblogs.com/hdtianfu/archive/2012/10/18/2730282.html