Windows核心編程學習筆記——-21章

來源:互聯網
上載者:User

第21章線程局部儲存區

有時將資料與一個對象的執行個體關聯起來是有協助的。比如視窗附加位元組通過使用SetWindowWord和SetWindowLong來將資料與一個指定的視窗關聯起來。我們可用線程局部儲存區(Thread Local Storage簡稱TLS)來將資料與一個正在執行的指定線程關聯起來。例如,可將建立線程的時間與線程關聯起來,當線程終止時,就可確定線程啟動並執行時間長度。

C/C++運行庫與TLS的聯絡:因其設計早於多線程,所以運行庫中大多數函數是單線程應用程式設計的。如_tcstok_s會將傳入的字串地址儲存在它自己的靜態變數中,當thread1調用時,該靜態變數儲存一個值,當thread2再調用時,該靜態變數的值被更改,若此時再調用thread1,則將不能得到想要的結果。為解決此問題,C/C++運行庫使用了TLS。C++運行庫會為每個線程分配獨立的字串指標,專供_tcstok_s使用。

若程式高度依賴全域變數和靜態變數,則TLS會成為救生符。所以開發時應盡量少用此類變數,更多使用自動變數(棧上的變數,其始終與特定線程關聯)和通過參數傳入的資料。

可在EXE和DLL中使用動態TLS和靜態TLS技術。一般來說,建立DLL時更有用,因DLL通常不知要被連結到的應用程式的結構。但編寫EXE時,一般知道要建立多少線程,如何使用這些線程,這樣就可用別的替代方案來為每個線程關聯資料;設計的好的話,可用基於棧的方法(局部變數)來為每個線程關聯資料。

21.1動態TLS

         原理:系統中每個進程都有一組正在使用標誌,每個標誌可被設為FREE或INUSE,表示該TLS元素是否正在使用。Microsoft保證至少有TLS_NIMINUM_AVAILABLE個位標誌可供使用(TLS_NIMINUM_AVAILABLE在WinNT.h中被定義為64,系統會在需要時分配更多的TLS元素)。每個線程建立時,系統自動分配TLS_NIMINUM_AVAILABLE個PVOID值,它們都初始化為0,並與線程關聯起來。進程位標誌數組元素個數與每個線程PVOID數組的元素個數相同。

         使用時,先讓系統檢索進程的位標誌來擷取第一個可用的FREE標誌的索引,然後將此索引儲存到線程的PVOID數組中,此索引不會再被其他線程所使用。

         用完後,通過TlsFree釋放已預定的TLS的元素,同時會將進程內的位標識數組中對應的INUSE標誌改回FREE,還會將所有線程中該元素的內容設為0。

步驟:

         第一步先調用TlsAlloc,讓系統對進程中的位標誌進行檢索並找到一個FREE標誌。然後將FREE改為INUSE並讓TlsAlloc返回該標誌在位元組中的索引。一個DLL通常將此索引儲存在一個全域變數中。因此值會在整個進程範圍內使用,而非線上程範圍內使用。

         第二步調用TlsSetValue將一個值放到調用線程的數組中。從線程的數組中取回值用TlsGetValue。

         第三步當不再需要一個已經預定的TLS元素時,應調用TlsFree。

使用動態TSL:

         若DLL要使用TLS,則會在DllMain處理DLL_PROCESS_ATTACH的時候調用TlsAlloc,在DllMain處理DLL_PROCESS_DETACH的時候調用TlsFree。而對TlsSetValue和TlsGetValue的調用最可能發生在DLL所提供的其他函數中。

21.2靜態TLS

         與動態TLS相似,靜態TLS也將資料與線程關聯起來。但使用時不必在代碼中調用任何函數,更易使用。

         若想將應用程式建立的每個線程與該線程的啟動時間關聯起來,只需聲明一個啟動時間:__declspec(thread) DWORD gt_dwStartTime = 0; __declspec(thread)首碼告訴編譯器應在可執行檔或DLL檔案中,把對應的變數與特定線程相關。此修飾符修飾的變數必須被聲明為全域變數或靜態變數。局部變數不可用此修飾符,因其已與特定線程相關聯。

 

DLL地獄問題:

比如現在建立好了一個DLL匯出了CMyClass類,客戶也能正常使用這個DLL,假設CMyClass對象的大小為30位元組。如果我們需要修改DLL 中的CMyClass類,讓它有相同的函數和成員變數,但是給增加了一個私人的成員變數int類型,現在CMyClass對象的大小就是34位元組了。當直接把這 個新的DLL給客戶使用替換掉原來30位元組大小的DLL,客戶應用程式期望的是30位元組大小的對象,而現在卻變成了一個34位元組大小的對象,糟糕,客戶程式出錯 了。

類似的問題,如果不是匯出CMyClass類,而在匯出的函數中使用了CMyClass,改變對象的大小仍然會有問題的。這個時候修改這個問題的唯一辦法就是替 換客戶程式中的CMyClass的標頭檔,全部重新編譯整個應用程式,讓客戶程式使用大小為34位元組的對象。

這就是一個嚴重的問題,有的時候如果沒有客戶程式的原始碼,那麼我們就不能使用這個新的DLL了。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.