• <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>

            統(tǒng)計(jì)

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

            留言簿(6)

            隨筆分類

            文章分類

            Link

            搜索

            •  

            積分與排名

            • 積分 - 166406
            • 排名 - 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-11-27 21:46 pear_li 閱讀(1208) 評(píng)論(0)  編輯 收藏 引用 所屬分類: windows kernel

            一本久道久久综合狠狠躁AV| 精品一区二区久久| 亚洲中文字幕久久精品无码喷水| 久久久精品人妻一区二区三区蜜桃| 亚洲级αV无码毛片久久精品| 奇米综合四色77777久久| 国产69精品久久久久99尤物| 性做久久久久久久久老女人| 久久久久亚洲AV无码麻豆| 国产精品日韩欧美久久综合| 久久久午夜精品福利内容| 秋霞久久国产精品电影院| 国产成人无码精品久久久性色 | 要久久爱在线免费观看| 97r久久精品国产99国产精| 99久久做夜夜爱天天做精品| 91精品日韩人妻无码久久不卡| 精品久久久中文字幕人妻| 国产亚洲精久久久久久无码AV| 久久综合综合久久综合| 国产精品乱码久久久久久软件| 日本免费久久久久久久网站| 97久久婷婷五月综合色d啪蜜芽| 久久丝袜精品中文字幕| 青青热久久综合网伊人| 国产成人久久精品激情| 久久综合国产乱子伦精品免费| 久久精品国产亚洲AV蜜臀色欲 | 久久精品国产一区二区电影| 久久亚洲国产欧洲精品一| 97久久超碰成人精品网站| 无码伊人66久久大杳蕉网站谷歌| 久久亚洲精品国产精品婷婷| 人人狠狠综合久久亚洲| 亚洲日本va午夜中文字幕久久 | 国产成年无码久久久免费| 久久经典免费视频| 久久精品中文无码资源站| 国产精品久久新婚兰兰| 亚洲欧美日韩中文久久| 久久久婷婷五月亚洲97号色 |