您可以使用受控線程本機記憶體 (TLS) 來儲存線程和應用程式域特有的數據。 .NET 提供兩種方式來使用受控的 TLS:執行緒相對靜態欄位和資料欄位。
如果您能在編譯時期預期切確的需求,請使用執行緒相對靜態欄位(Visual Basic 中的執行緒相對
Shared欄位)。 執行緒相對的靜態欄位提供最佳效能。 它們同時提供編譯時類型檢查的優點。當你的實際需求可能只有在執行時才會被發現時,就使用資料插槽。 資料插槽的速度比執行緒相對靜態欄位更慢且使用上更不便,而且資料會儲存為類型 Object,因此您必須先將它轉換成正確的類型,才能使用它。
在非受控 C++ 中,您可以使用 TlsAlloc 來動態配置位置,並使用 __declspec(thread) 宣告變數應該配置在線程相對儲存區中。 線程相關的靜態欄位和資料槽提供了這種行為的管理版。
您可以使用 System.Threading.ThreadLocal<T> 類別來建立執行緒區域物件,這些物件在第一次被取用時會以延遲方式初始化。 如需詳細資訊,請參閱 延遲初始化。
受控 TLS 中數據的唯一性
無論您使用線程相對靜態欄位或資料插槽,受控 TLS 中的資料都是針對線程和應用程式域組合而唯一的。
在應用程式域中,即使兩個線程都使用相同的欄位或位置,一個線程也無法修改來自另一個線程的數據。
當線程從多個應用程式域存取相同的欄位或位置時,每個應用程式域中都會維護個別的值。
例如,如果線程設定線程相關靜態字段的值,進入另一個應用程式域,然後擷取字段的值,則第二個應用程式域中擷取的值與第一個應用程式域中的值不同。 為第二個應用程式域中的欄位設定新值不會影響第一個應用程式域中的域值。
同樣地,當線程在兩個不同的應用程式域中取得相同的具名數據位置時,第一個應用程式域中的數據會與第二個應用程式域中的數據無關。
Thread-Relative 靜態欄位
如果您知道某個數據一律對線程和應用程式域組合而言是唯一的,請將 ThreadStaticAttribute 屬性套用至靜態字段。 使用欄位,就像使用任何其他靜態欄位一樣。 欄位中的數據對使用該欄位的每個線程而言都是唯一的。
執行緒相對靜態欄位在效能上優於數據槽,且具有編譯時類型檢查的優勢。
請注意,任何類別建構函式程式代碼都會在存取欄位的第一個內容中的第一個線程上執行。 在相同應用程式域中的所有其他線程或內容中,如果欄位是參考型別,則欄位會初始化為 null (Nothing 在 Visual Basic 中為 ),如果是實值型別,則會初始化為預設值。 因此,您不應該依賴類別建構函式來初始化線程相對靜態字段。 相反地,請避免初始化線程相對靜態欄位,並假設它們已初始化為 null (Nothing) 或其預設值。
資料槽
.NET 提供線程和應用程式域組合唯一的動態數據位置。 數據位置有兩種類型:具名插槽和未命名的插槽。 兩者都是透過使用 LocalDataStoreSlot 結構來實作。
若要建立具名數據位置,請使用 Thread.AllocateNamedDataSlot 或 Thread.GetNamedDataSlot 方法。 若要取得現有命名插槽的參考,請將其名稱傳入 GetNamedDataSlot 方法。
若要建立未命名的數據位置,請使用 Thread.AllocateDataSlot 方法。
針對具名和未命名的插槽,請使用 Thread.SetData 和 Thread.GetData 方法來設定和擷取位置中的資訊。 這些是靜態方法,一律會處理目前正在執行之線程的數據。
命名插槽可能很方便,因為您可以在需要時藉由將其名稱傳遞給GetNamedDataSlot方法來擷取插槽,而不是維護未命名插槽的參考。 不過,如果另一個元件針對其線程相對記憶體使用相同的名稱,而線程會從您的元件和其他元件執行程式碼,則兩個元件可能會損毀彼此的數據。 (此案例假設這兩個元件都在相同的應用程式域中執行,而且它們不是設計來共用相同的數據。