執行緒區域儲存區

執行緒區域儲存區 (Thread Local Storage,TLS) 是一種方法,讓指定之多執行緒處理序中的每個執行緒用來配置位置,以儲存執行緒特定資料。 (TlsAlloc) 的 TLS API 可支援動態系結 (執行時間) 執行緒特定資料。 除了現有的 API 執行之外,Win32 和 Microsoft c + + 編譯器現在支援靜態系結 (載入時間) 每個執行緒的資料。

TLS 的編譯器實作

C + + 11:thread_local儲存類別規範是針對物件和類別成員指定執行緒區域儲存區的建議方式。 如需詳細資訊,請參閱 (c + +) 的儲存體類別

MSVC 也會提供 Microsoft 專屬的屬性( thread)作為擴充儲存類別修飾詞。 __declspec使用關鍵字來 thread 宣告變數。 例如,下列程式碼宣告整數執行緒區域變數,並使用值將它初始化:

__declspec( thread ) int tls_i = 1;

規則與限制

當您宣告靜態繫結的執行緒區域物件和變數時,必須遵守下列指導方針: 這些指導方針適用于 執行緒thread_local

  • thread屬性只能套用至類別和資料宣告和定義。 它不能用在函式宣告或定義上。 例如,下列程式碼會產生編譯器錯誤:

    __declspec( thread )void func();     // This will generate an error.
    
  • thread修飾詞只能在具有 static 範圍的資料項目上指定。 這包括全域資料物件 (staticextern) 、本機靜態物件,以及 c + + 類別的靜態資料成員。 無法使用 thread 屬性宣告自動資料物件。 下列程式碼會產生編譯器錯誤:

    void func1()
    {
        __declspec( thread )int tls_i;            // This will generate an error.
    }
    
    int func2(__declspec( thread )int tls_i )     // This will generate an error.
    {
        return tls_i;
    }
    
  • 執行緒區域物件的宣告和定義都必須指定 thread 屬性。 例如,下列程式碼會產生錯誤:

    #define Thread  __declspec( thread )
    extern int tls_i;        // This will generate an error, since the
    int __declspec( thread )tls_i;        // declaration and definition differ.
    
  • thread無法使用屬性做為類型修飾詞。 例如,下列程式碼會產生編譯器錯誤:

    char __declspec( thread ) *ch;        // Error
    
  • 由於允許使用 thread 屬性的 c + + 物件宣告,因此下列兩個範例在語義上是相等的:

    __declspec( thread ) class B
    {
    // Code
    } BObject;  // OK--BObject is declared thread local.
    
    class B
    {
    // Code
    };
    __declspec( thread ) B BObject;  // OK--BObject is declared thread local.
    
  • 執行緒區域物件的位址不會被視為常數,而且牽涉到這類位址的任何運算式都不會被視為常數運算式。 在標準 C 中,效果是禁止使用執行緒區域變數的位址做為物件或指標的初始化運算式。 例如,C 編譯器會將下列程式碼標示為錯誤:

    __declspec( thread ) int tls_i;
    int *p = &tls_i;       //This will generate an error in C.
    

    這項限制不適用於 c + +。 因為 C++ 允許所有物件的動態初始化,所以您可使用採用執行緒區域變數位址的運算式來初始化物件。 它的執行方式就如同執行緒區域物件的結構。 例如,稍早所示的程式碼在編譯為 c + + 原始程式檔時,不會產生錯誤。 執行緒區域變數的位址只有在取得位址的執行緒仍然存在時才有效。

  • 標準 C 允許使用牽涉到本身參考的運算式來初始化物件或變數,但僅適用于非靜態範圍的物件。 雖然 c + + 通常會允許物件的這類動態初始化,以及包含對本身之參考的運算式,但這種初始化不允許搭配執行緒區域物件。 例如:

    __declspec( thread )int tls_i = tls_i;                // Error in C and C++
    int j = j;                               // OK in C++, error in C
    __declspec( thread )int tls_i = sizeof( tls_i )       // Legal in C and C++
    

    sizeof包含要初始化之物件的運算式,並不代表對本身的參考,而且會在 c 和 c + + 中啟用。

    C + + 不允許執行緒資料的動態初始化,因為未來可能會增強執行緒區域儲存設備。

  • 在 Windows Vista __declspec( thread ) 之前 Windows 作業系統上有一些限制。 如果 DLL 將任何資料或物件宣告為 __declspec( thread ) ,則會在動態載入時造成保護錯誤。 使用 LoadLibrary載入 DLL 之後,每當程式碼參考 __declspec( thread ) 資料時,就會導致系統失敗。 因為執行緒的全域變數空間是在執行階段進行配置,所以此空間的大小是以應用程式的需求,再加上以靜態方式連結之所有 DLL 的需求的計算為基礎。 當您使用 LoadLibrary 時,您無法擴充此空間,以允許使用 __declspec( thread ) 宣告的執行緒區域變數。 如果 DLL 可能已載入 LoadLibrary ,請在您的 dll 中使用 Tls api (例如TlsAlloc)來配置 tls。

另請參閱

使用 C 和 Win32 進行多執行緒處理