青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

統計

  • 隨筆 - 50
  • 文章 - 42
  • 評論 - 147
  • 引用 - 0

留言簿(6)

隨筆分類

文章分類

Link

搜索

  •  

積分與排名

  • 積分 - 167517
  • 排名 - 159

最新評論

閱讀排行榜

評論排行榜

使用線程局部存儲TLS

Thread local storage (TLS)統一進程的多個線程可以通過由TlsAlloc方法返回的索引值在線程自身的空間內存儲和取回一個值。在以下這個例子里,索引值在進程開始時創建,當各個線程啟動時,會各自申請一塊動態內存并且將內存指針通過TlsSetValue方法存儲到各自的TLS空間中(由先前的索引值標定)。CommonFunc方法使用TlsGetValue方法通過索引取得數據指針。在各個線程結束前,釋放動態內存塊。在進程結束見,調用TlsFree方法釋放索引。

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

90

常用情景:
各個線程所處理的對象有所不同,但是所需要的處理卻可能類似,例如多個線程同時處理多個文件,就可以將文件句柄存在在相應的Tls中,在使用相同的接口進行處理
背景知識:
每個線程除了共享進程的資源外還擁有各自的私有資源:一個寄存器組(或者說是線程上下文);一個專屬的堆棧;一個專屬的消息隊列;一個專屬的Thread Local Storage(TLS);一個專屬的結構化異常處理串鏈。
TLS 是一個良好的Win32 特質,讓多線程程序設計更容易一些。TLS 是一個機制,經由它,程序可以擁有全域變量,但在不同的線程里有不同的值。也就是說,進程中的所有線程都可以擁有全域變量,但這些變量其實是特定對某個線程才有意義。例如,你可能有一個多線程程序,每一個線程都對不同的文件寫文件(也因此它們使用不同的文件handle)。這種情況下,把每一個線程所使用的文件handle 儲存在TLS 中,將會十分方便。當線程需要知道所使用的handle,它可以從TLS 獲得。重點在于:線程用來取得文件handle 的那一段碼在任何情況下都是相同的,而從TLS中取出的文件handle 卻各不相同。非常靈巧,不是嗎?有全域變數的便利,卻又分屬各線程。

 

  雖然TLS 很方便,它并不是毫無限制。在Windows NT 和Windows 95 之中,有64 個DWORD slots 供每一個線程使用。這意思是一個進程最多可以有64 個「對各線程有不同意義」的DWORDs。 雖然TLS 可以存放單一數值如文件handle,更常的用途是放置指針,指向線程的私有資料。有許多情況,多線程程序需要儲存一堆數據,而它們又都是與各線程相關。許多程序員對此的作法是把這些變量包裝為C 結構,然后把結構指針儲存在TLS 中。當新的線程誕生,程序就配置一些內存給該結構使用,并且把指針儲存在為線程保留下來的TLS 中。一旦線程結束,程序代碼就釋放所有配置來的區塊。既然每一個線程都有64 個slots 用來儲存線程自己的數據,那么這些空間到底打哪兒來?在線程的學習中我們可以從結構TDB中看到,每一個thread database 都有64 個DWORDs 給TLS 使用。當你以TLS 函式設定或取出數據,事實上你真正面對的就是那64 DWORDs。好,現在我們知道了原來那些“對各線程有不同意義的全局變量”是存放在線程各自的TDB中阿。
 
    接下來你也許會問:我怎么存取這64個DWORDS呢?我又怎么知道哪個DWORDS被占用了,哪個沒有被占用呢?首先我們要理解這樣一個事實:系統之所以給我們提供TLS這一功能,就是為了方便的實現“對各線程有不同意義的全局變量”這一功能;既然要達到“全局變量”的效果,那么也就是說每個線程都要用到這個變量,既然這樣那么我們就不需要對每個線程的那64個DWORDS的占用情況分別標記了,因為那64個DWORDS中的某一個一旦占用,是所有線程的那個DWORD都被占用了,于是KERNEL32 使用兩個DWORDs(總共64 個位)來記錄哪一個slot 是可用的、哪一個slot 已經被用。這兩個DWORDs 可想象成為一個64 位數組,如果某個位設立,就表示它對應的TLS slot 已被使用。這64 位TLS slot 數組存放在process database 中(在進程一節中的PDB結構中我們列出了那兩個DWORDs)。
 
下面的四個函數就是對TLS進行操作的:

  (1)TlsAlloc  

上面我們說過了KERNEL32 使用兩個DWORDs(總共64 個位)來記錄哪一個slot 是可用的、哪一個slot 已經被用。當你需要使用一個TLS slot 的時候,你就可以用這個函數將相應的TLS slot位置1。 

 (2)TlsSetValue  

TlsSetValue 可以把數據放入先前配置到的TLS slot 中。兩個參數分別是TLS slot 索引值以及欲寫入的數據內容。TlsSetValue 就把你指定的數據放入64 DWORDs 所組成的數組(位于目前的thread database)的適當位置中。  

 (3)TlsGetValue  

這個函數幾乎是TlsSetValue 的一面鏡子,最大的差異是它取出數據而非設定數據。和TlsSetValue 一樣,這個函數也是先檢查TLS 索引值合法與否。如果是,TlsGetValue 就使用這個索引值找到64 DWORDs 數組(位于thread database 中)的對應數據項,并將其內容傳回。  

 (4)TlsFree  

這個函數將TlsAlloc 和TlsSetValue 的努力全部抹消掉。TlsFree 先檢驗你交給它的索引值是否的確被配置過。如果是,它將對應的64 位TLS slots 位關閉。然后,為了避免那個已經不再合法的內容被使用,TlsFree 巡訪進程中的每一個線程,把0 放到剛剛被釋放的那個TLS slot 上頭。于是呢,如果有某個TLS 索引后來又被重新配置,所有用到該索引的線程就保證會取回一個0 值,除非它們再調用TlsSetValue。

posted on 2008-12-10 21:25 pear_li 閱讀(2141) 評論(4)  編輯 收藏 引用 所屬分類: C++

評論

# re: 使用線程局部存儲TLS  2008-12-11 09:47 LOGOS

終究是線程 “局部” 存儲,看不出和傳參給線程相比,優勢在哪里
  回復  更多評論    

# re: 使用線程局部存儲TLS  2008-12-11 16:36 阿福

我覺得線程局部存儲的優勢不大,除非和編譯器結合起來。
比如,在線程函數的棧上定義一個對象,在線程函數退出的時候,對象自動調用自己的析構函數清理空間,同樣能夠達到線程局部存儲的效果。

所謂線程局部存儲與編譯器結合,是指這樣的效果:
TLS int errno;
//假設存在關鍵字TLS,這樣在全局聲明的變量,就會被編譯器自動編譯為線程局部存儲的變量??上Ф紱]編譯器支持這樣的操作,相信最新的支持并行的語言會有類似的功能。
  回復  更多評論    

# re: 使用線程局部存儲TLS  2008-12-12 09:45 guest

@LOGOS

當線程不是自己創建那么就很有用了。

假設A線程會依次執行fun1,fun2,fun3函數(或者回調吧),fun1要傳遞一些似有數據給fun3怎么辦?使用全局變量的時候要處理同步問題,用TLS就不存在這個問題了。最經常見到的應用是標準庫里面的strtok等。

------------------------------
C / C + +運行期庫要使用線程本地存儲器(T L S)。由于運行期庫是在多線程應用程序出現前
的許多年設計的,因此運行期庫中的大多數函數是用于單線程應用程序的。函數 s t r t o k就是個
很好的例子。應用程序初次調用 s t r t o k時,該函數傳遞一個字符串的地址,并將字符串的地址
保存在它自己的靜態變量中。當你將來調用s t r t o k函數并傳遞N U L L時,該函數就引用保存的字
符串地址。
在多線程環境中,一個線程可以調用 s t r t o k,然后,在它能夠再次調用該函數之前,另一
個線程也可以調用 S t r t o k。在這種情況下,第二個線程會在第一個線程不知道的情況下,讓
s t r t o k用一個新地址來改寫它的靜態變量。第一個線程將來調用 s t r t o k時將使用第二個線程的字
符串,這就會導致各種各樣難以發現和排除的錯誤。
為了解決這個問題,C / C + +運行期庫使用了T L S。每個線程均被賦予它自己的字符串指針,
供s t r t o k函數使用。需要予以同樣對待的其他C / C + +運行期庫函數還有a s c t i m e和g m t i m e。
如果你的應用程序需要嚴重依賴全局變量或靜態變量,那么T L S能夠幫助解決它遇到的問題。
但是編程人員往往盡可能減少對這些變量的使用,而更多地依賴自動(基于堆棧的)變量和通過
函數的參數傳遞的數據。這樣做是很好的,因為基于堆棧的變量總是與特定的線程相聯系的。
標準的C運行期庫一直是由許多不同的編譯器供應商來實現和重新實現的。如果 C編譯器
不包含標準的C運行期庫,那么就不值得去購買它。編程員多年來一直使用標準的 C運行期庫,
并且將會繼續使用它,這意味著s t r t o k之類的函數的原型和行為特性必須與上面所說的標準C運
行期庫完全一樣。如果今天重新來設計C運行期庫,那么它就必須支持多線程應用程序的環境,
并且必須采取相應的措施來避免使用全局變量和靜態變量。
在我的軟件開發項目中,我總是盡可能避免使用全局變量和靜態變量。如果你的應用程序
使用全局變量和靜態變量,那么建議你務必觀察每個變量,并且了解一下它能否改變成基于堆
棧的變量。如果打算將線程添加給應用程序,那么這樣做可以節省大量時間,甚至單線程應用
程序也能夠從中得到許多好處。
  回復  更多評論    

# re: 使用線程局部存儲TLS  2008-12-12 18:01 阿福

樓上的老兄說的對,其思想也就是在編譯器級別支持線程局部存儲的意思吧!
比如現在C標準庫的errno是這樣的定義
#define errno geterrno()
表面上看是一個變量,而實際上去調用一個函數來實現。
在函數里面實現了將數據存儲在自己的棧里面。
  回復  更多評論    
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久久高清一区二区三区| 香蕉久久夜色精品国产| av不卡在线观看| 黄色成人在线网站| 正在播放日韩| 国产精品国产福利国产秒拍| 国产日韩综合一区二区性色av| 欧美福利视频一区| 国产欧美欧美| 亚洲一区二区三区免费观看| 亚洲精品在线免费观看视频| 久久久精品一区二区三区| 欧美亚洲日本一区| 国产精品久久久久久久第一福利| 亚洲黄色av| 亚洲国产精品t66y| 久久久女女女女999久久| 久久国产乱子精品免费女| 国产精品无码专区在线观看| 一区二区三区欧美| 一区二区三区 在线观看视| 欧美—级a级欧美特级ar全黄| 欧美成人精品福利| 亚洲第一级黄色片| 麻豆精品视频| 宅男噜噜噜66国产日韩在线观看| 久久国产一区| 巨乳诱惑日韩免费av| 国模套图日韩精品一区二区| 欧美在线亚洲综合一区| 久久只有精品| 亚洲国内自拍| 欧美精品亚洲二区| 亚洲精品久久久一区二区三区| 亚洲伦理中文字幕| 欧美日韩一二三区| 一区二区三区高清在线| 欧美亚洲一区| 狠狠色2019综合网| 老司机精品导航| 亚洲人成艺术| 亚洲欧美色婷婷| 国产日韩成人精品| 久久亚洲精品一区二区| 欧美黑人多人双交| 一区二区三区欧美激情| 国产精品久久亚洲7777| 午夜免费在线观看精品视频| 美女黄毛**国产精品啪啪 | 欧美精品三级在线观看| 亚洲精品国产系列| 亚洲欧美一区二区激情| 狠狠色综合网| 欧美激情综合五月色丁香小说| 亚洲黄页一区| 性做久久久久久久久| 在线观看一区视频| 欧美视频中文一区二区三区在线观看 | 久久性天堂网| 99视频超级精品| 久久激情五月婷婷| 日韩视频三区| 国产亚洲一区在线播放| 欧美激情一区二区| 欧美在线播放一区| 亚洲激情黄色| 久久久亚洲国产天美传媒修理工 | 亚洲欧美资源在线| 亚洲第一天堂av| 欧美中文字幕视频在线观看| 亚洲日韩欧美视频| 国产午夜精品在线| 欧美国产日产韩国视频| 欧美在线观看视频在线 | 先锋亚洲精品| 99精品免费网| 免播放器亚洲一区| 国产精品国产福利国产秒拍| 国产精品久久久久天堂| 久久超碰97人人做人人爱| 亚洲黄网站在线观看| 久久gogo国模啪啪人体图| 99国产精品久久久久久久久久 | 久久精品一区四区| 一本色道久久综合亚洲91| 欧美成人在线网站| 久久精品亚洲国产奇米99| 亚洲视频欧洲视频| 亚洲日本欧美| 在线看片欧美| 精品白丝av| 国产精品丝袜白浆摸在线| 欧美理论大片| 免费视频最近日韩| 久久久亚洲国产美女国产盗摄| 亚洲永久在线| 国产精品99久久久久久久女警 | 麻豆国产精品一区二区三区| 亚洲欧美另类国产| 一区二区欧美亚洲| 一本不卡影院| 亚洲精品五月天| 91久久精品一区二区三区| 一区二区在线不卡| 一区二区三区在线观看欧美| 国产在线不卡精品| 国产日韩欧美综合| 国产亚洲欧美激情| 国产亚洲欧美aaaa| 国产亚洲视频在线| 国产在线精品二区| 红桃视频一区| 亚洲大片在线| 亚洲精品欧美一区二区三区| 亚洲精品日本| 在线视频一区二区| 亚洲一本视频| 午夜精品福利一区二区三区av| 亚洲一区欧美一区| 小黄鸭精品aⅴ导航网站入口| 欧美一区二区三区另类 | 亚洲区第一页| 亚洲精品激情| 亚洲美女电影在线| 日韩亚洲欧美中文三级| 一区二区三区不卡视频在线观看| 亚洲一区二区在线免费观看视频| 亚洲一区二区免费看| 午夜在线一区| 久久裸体艺术| 欧美激情视频一区二区三区免费 | 久久久成人网| 欧美肥婆bbw| 91久久综合亚洲鲁鲁五月天| 夜夜嗨av一区二区三区四区| 亚洲欧美精品| 久久看片网站| 欧美日韩一区二区欧美激情| 国产伦精品一区二区三区在线观看 | 欧美国产另类| 欧美日一区二区三区在线观看国产免| 欧美午夜精品久久久久免费视| 国产欧美一区二区三区久久人妖| 黄色成人av网站| 亚洲视频中文| 久久久夜夜夜| 亚洲巨乳在线| 久久岛国电影| 欧美视频在线观看| 国产亚洲欧美激情| 99成人在线| 久久精品一区中文字幕| 亚洲黄色尤物视频| 欧美伊久线香蕉线新在线| 欧美高清在线视频观看不卡| 国产精品一二三四| 亚洲国产精品久久精品怡红院| 亚洲综合国产激情另类一区| 老司机免费视频一区二区三区| 亚洲乱码视频| 久久亚洲春色中文字幕| 国产精品一二三四区| 日韩天天综合| 久久久久久穴| 99国产精品久久久久久久久久 | 另类春色校园亚洲| 国产精品日韩欧美一区二区| 亚洲精品少妇网址| 久久日韩精品| 亚洲一品av免费观看| 欧美不卡视频一区发布| 国产亚洲欧美激情| 亚洲一区二区成人在线观看| 欧美激情视频给我| 性久久久久久久久久久久| 欧美视频第二页| 亚洲精品美女在线观看播放| 久久精品水蜜桃av综合天堂| 一本久久a久久免费精品不卡| 欧美国产高清| 亚洲国产精品一区二区www| 久久久久久亚洲精品杨幂换脸| 亚洲伊人伊色伊影伊综合网| 欧美日韩免费在线视频| 亚洲人体一区| 亚洲第一在线综合网站| 久久婷婷影院| 在线观看国产日韩| 久久色中文字幕| 羞羞视频在线观看欧美| 国产精品久久久久999| 亚洲私人黄色宅男| 夜夜嗨av色综合久久久综合网| 欧美伦理影院| 亚洲视频二区| 一区二区电影免费在线观看| 欧美午夜一区二区福利视频| 亚洲视频成人| 亚洲一区二区三区国产| 国产精品免费福利|