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

統(tǒng)計(jì)

  • 隨筆 - 50
  • 文章 - 42
  • 評(píng)論 - 147
  • 引用 - 0

留言簿(6)

隨筆分類

文章分類

Link

搜索

  •  

積分與排名

  • 積分 - 167183
  • 排名 - 159

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

使用線程局部存儲(chǔ)TLS

Thread local storage (TLS)統(tǒng)一進(jìn)程的多個(gè)線程可以通過(guò)由TlsAlloc方法返回的索引值在線程自身的空間內(nèi)存儲(chǔ)和取回一個(gè)值。在以下這個(gè)例子里,索引值在進(jìn)程開(kāi)始時(shí)創(chuàng)建,當(dāng)各個(gè)線程啟動(dòng)時(shí),會(huì)各自申請(qǐng)一塊動(dòng)態(tài)內(nèi)存并且將內(nèi)存指針通過(guò)TlsSetValue方法存儲(chǔ)到各自的TLS空間中(由先前的索引值標(biāo)定)。CommonFunc方法使用TlsGetValue方法通過(guò)索引取得數(shù)據(jù)指針。在各個(gè)線程結(jié)束前,釋放動(dòng)態(tài)內(nèi)存塊。在進(jìn)程結(jié)束見(jiàn),調(diào)用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

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

 

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

  (1)TlsAlloc  

上面我們說(shuō)過(guò)了KERNEL32 使用兩個(gè)DWORDs(總共64 個(gè)位)來(lái)記錄哪一個(gè)slot 是可用的、哪一個(gè)slot 已經(jīng)被用。當(dāng)你需要使用一個(gè)TLS slot 的時(shí)候,你就可以用這個(gè)函數(shù)將相應(yīng)的TLS slot位置1。 

 (2)TlsSetValue  

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

 (3)TlsGetValue  

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

 (4)TlsFree  

這個(gè)函數(shù)將TlsAlloc 和TlsSetValue 的努力全部抹消掉。TlsFree 先檢驗(yàn)?zāi)憬唤o它的索引值是否的確被配置過(guò)。如果是,它將對(duì)應(yīng)的64 位TLS slots 位關(guān)閉。然后,為了避免那個(gè)已經(jīng)不再合法的內(nèi)容被使用,TlsFree 巡訪進(jìn)程中的每一個(gè)線程,把0 放到剛剛被釋放的那個(gè)TLS slot 上頭。于是呢,如果有某個(gè)TLS 索引后來(lái)又被重新配置,所有用到該索引的線程就保證會(huì)取回一個(gè)0 值,除非它們?cè)僬{(diào)用TlsSetValue。

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

評(píng)論

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

終究是線程 “局部” 存儲(chǔ),看不出和傳參給線程相比,優(yōu)勢(shì)在哪里

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

我覺(jué)得線程局部存儲(chǔ)的優(yōu)勢(shì)不大,除非和編譯器結(jié)合起來(lái)。
比如,在線程函數(shù)的棧上定義一個(gè)對(duì)象,在線程函數(shù)退出的時(shí)候,對(duì)象自動(dòng)調(diào)用自己的析構(gòu)函數(shù)清理空間,同樣能夠達(dá)到線程局部存儲(chǔ)的效果。

所謂線程局部存儲(chǔ)與編譯器結(jié)合,是指這樣的效果:
TLS int errno;
//假設(shè)存在關(guān)鍵字TLS,這樣在全局聲明的變量,就會(huì)被編譯器自動(dòng)編譯為線程局部存儲(chǔ)的變量。可惜都沒(méi)編譯器支持這樣的操作,相信最新的支持并行的語(yǔ)言會(huì)有類似的功能。

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

@LOGOS

當(dāng)線程不是自己創(chuàng)建那么就很有用了。

假設(shè)A線程會(huì)依次執(zhí)行fun1,fun2,fun3函數(shù)(或者回調(diào)吧),fun1要傳遞一些似有數(shù)據(jù)給fun3怎么辦?使用全局變量的時(shí)候要處理同步問(wèn)題,用TLS就不存在這個(gè)問(wèn)題了。最經(jīng)常見(jiàn)到的應(yīng)用是標(biāo)準(zhǔn)庫(kù)里面的strtok等。

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

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

樓上的老兄說(shuō)的對(duì),其思想也就是在編譯器級(jí)別支持線程局部存儲(chǔ)的意思吧!
比如現(xiàn)在C標(biāo)準(zhǔn)庫(kù)的errno是這樣的定義
#define errno geterrno()
表面上看是一個(gè)變量,而實(shí)際上去調(diào)用一個(gè)函數(shù)來(lái)實(shí)現(xiàn)。
在函數(shù)里面實(shí)現(xiàn)了將數(shù)據(jù)存儲(chǔ)在自己的棧里面。
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲精品美女| 亚洲精品美女在线观看| 久久精品30| 久久九九电影| 麻豆成人综合网| 欧美激情 亚洲a∨综合| 欧美久久电影| 国产精品夜夜夜一区二区三区尤| 国产精品自拍网站| 精品成人在线| 亚洲免费成人av电影| 午夜一区在线| 欧美激情1区2区3区| 在线一区欧美| 午夜精品久久久久久久久久久| 午夜精品久久久99热福利| 久久久久五月天| 亚洲国产视频a| 亚洲欧美精品一区| 蜜桃av噜噜一区| 国产精品高清网站| 伊大人香蕉综合8在线视| 亚洲一区二区在线看| 老牛影视一区二区三区| 亚洲精品网站在线播放gif| 欧美亚洲尤物久久| 欧美日韩精品系列| 亚洲第一在线综合在线| 亚洲欧美中文日韩v在线观看| 欧美大片在线看免费观看| 亚洲综合成人在线| 欧美日韩午夜剧场| 亚洲国内精品| 狼狼综合久久久久综合网| 亚洲小视频在线| 欧美日韩国产系列| 亚洲欧洲视频在线| 美女成人午夜| 久久国产精品久久久| 欧美日韩亚洲不卡| 亚洲美女视频在线观看| 欧美不卡在线| 久久久久国色av免费观看性色| 国产精品草莓在线免费观看| 日韩一区二区精品| 亚洲国产天堂久久国产91| 快she精品国产999| 在线免费观看日本一区| 麻豆成人综合网| 久久久精品性| 亚洲国产视频a| 亚洲第一毛片| 欧美精品播放| 中文av一区二区| 日韩视频精品| 欧美午夜片在线观看| 亚洲自拍偷拍一区| 亚洲一区二区欧美日韩| 国产精品丝袜久久久久久app| 午夜伦理片一区| 亚洲专区在线视频| 国产欧美丝祙| 久久亚洲不卡| 美女尤物久久精品| 亚洲美女在线一区| 亚洲深夜福利视频| 国产亚洲欧洲一区高清在线观看| 久久综合亚州| 欧美乱妇高清无乱码| 亚洲欧美日韩系列| 久久福利影视| 亚洲精品视频在线| 这里只有精品电影| 国内精品久久久久久久影视麻豆 | 国产伦精品一区二区三区四区免费 | 久久精品女人的天堂av| 欧美中文在线字幕| 亚洲第一区在线| 亚洲日本成人在线观看| 国产精品久久毛片a| 久久久精品日韩欧美| 另类人畜视频在线| 亚洲亚洲精品三区日韩精品在线视频 | 欧美久久一区| 欧美怡红院视频| 久久综合国产精品台湾中文娱乐网| 亚洲蜜桃精久久久久久久| 亚洲性av在线| 最新日韩在线| 亚洲欧美国产制服动漫| 亚洲国产精品久久久| 宅男噜噜噜66一区二区| 亚洲国产精品久久久久| 亚洲午夜日本在线观看| 在线播放中文一区| 亚洲午夜av在线| 亚洲精品社区| 久久久综合精品| 欧美一级在线播放| 欧美激情精品久久久久久蜜臀| 久久成人免费日本黄色| 欧美精品在线观看播放| 久久久久一本一区二区青青蜜月| 欧美日韩精品二区| 欧美福利在线观看| 国产在线拍偷自揄拍精品| 日韩一区二区精品在线观看| 亚洲电影免费| 久久久精彩视频| 久久本道综合色狠狠五月| 欧美视频第二页| 亚洲精品久久| 日韩视频在线一区二区| 老**午夜毛片一区二区三区| 久久精品一区二区三区不卡牛牛| 国产精品视频区| 中日韩男男gay无套| 一本久道久久久| 欧美精品一区二| 亚洲国产一区二区三区青草影视| 亚洲福利av| 免费日韩av| 欧美成人免费在线视频| 国产亚洲一级高清| 欧美在线三区| 久久精品国产清高在天天线| 国产精品久久久久av| 99精品视频免费全部在线| 欧美体内she精视频| 亚洲国产一区在线| 亚洲人成小说网站色在线| 久久久精品国产免大香伊 | 国产伦精品一区二区三区照片91| 欧美成人一二三| 在线成人激情| 久久久精品五月天| 久久久国产精品一区二区中文| 国产精品久久久久免费a∨| 99这里只有精品| 亚洲综合色自拍一区| 国产精品日日摸夜夜摸av| 在线中文字幕不卡| 亚洲综合丁香| 国产久一道中文一区| 亚洲男人的天堂在线aⅴ视频| 亚洲欧美成人网| 国产精品一二三视频| 性欧美大战久久久久久久久| 久久国产夜色精品鲁鲁99| 国产亚洲va综合人人澡精品| 午夜国产精品影院在线观看| 久久成人免费日本黄色| 激情成人综合| 欧美高清视频www夜色资源网| 亚洲精品久久久一区二区三区| 亚洲作爱视频| 国产美女一区| 久久精品视频一| 亚洲国产va精品久久久不卡综合| 日韩亚洲成人av在线| 欧美婷婷久久| 欧美亚洲免费| 亚洲国产欧美日韩另类综合| 亚洲私人影院| 韩曰欧美视频免费观看| 免费亚洲一区二区| 亚洲图片欧洲图片日韩av| 久久尤物电影视频在线观看| 亚洲美女福利视频网站| 国产精品日韩欧美综合| 免费久久99精品国产| 亚洲一本视频| 欧美激情日韩| 亚洲欧美久久| 91久久夜色精品国产九色| 国产精品一区二区在线观看| 欧美成人高清视频| 欧美在线一区二区| 一本大道av伊人久久综合| 麻豆国产精品777777在线 | 亚洲人成网站精品片在线观看 | 欧美视频一区二区三区在线观看| 性亚洲最疯狂xxxx高清| 亚洲盗摄视频| 久久久久久九九九九| 在线一区二区三区做爰视频网站| 黄色成人在线观看| 国产精品美女久久久久久免费 | 黄色日韩精品| 久久电影一区| 亚洲视频在线观看视频| 伊人精品成人久久综合软件| 欧美日韩小视频| 噜噜噜躁狠狠躁狠狠精品视频| 亚洲一二三区精品| 亚洲日本va午夜在线电影| 免费成人网www| 久久久综合网| 久久国产主播| 亚洲欧美中文日韩v在线观看|