共用方式為


TLS 的規則和限制

在宣告靜態繫結執行緒區域物件和變數時必須遵守下列方針:

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

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

    #define Thread  __declspec( thread )
    void func1()
    {
        Thread int tls_i;            // This will generate an error.
    }
    
    int func2( 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 Thread tls_i;        // declaration and definition differ.
    
  • thread 屬性不能用來當做型別修飾詞。 例如,下列程式碼會產生編譯器錯誤:

    char __declspec( thread ) *ch;        // Error
    
  • C++ 類別不能使用 thread 屬性。 然而,C++ 類別物件可以使用 thread 屬性來加以執行個體化。 例如,下列程式碼會產生編譯器錯誤:

    #define Thread  __declspec( thread )
    class Thread C       // Error: classes cannot be declared Thread.
    {
    // Code
    };
    C CObject;
    

    因為允許使用 thread 屬性的 C++ 物件宣告,下列兩個範例在語意上是相同的:

    #define Thread  __declspec( thread )
    Thread class B
    {
    // Code
    } BObject;               // OK--BObject is declared thread local.
    
    class B
    {
    // Code
    };
    Thread B BObject;        // OK--BObject is declared thread local.
    
  • 執行緒區域物件的位址並不被認為是常數,而且任何包含這種位址的運算式不會被視為常數運算式。 在標準的 C 中,這樣做的效果是用來禁止將執行緒區域變數的位址用來當做物件或指標的初始設定式。 例如,C 編譯器會將下列程式碼標示為錯誤:

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

    這項限制不適用於 C++。 因為 C++ 允許所有物件的動態初始化,您可以使用具執行緒區域變數位址的運算式來初始化物件。 完成的方式與執行緒區域物件的建構相同。 例如,先前顯示的程式碼在當做 C++ 原始程式檔編譯時不會產生錯誤。 注意執行緒區域變數的位址只有在採用這個位址的執行緒仍然存在時才有效。

  • 標準的 C 允許使用需要自我參考的運算式來初始化物件或變數,但只限於非靜態範圍的物件。 雖然 C++ 通常允許使用需要自我參考的運算式來對物件進行動態初始化,但這種類型的初始化不適用於執行緒區域物件。 例如:

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

    請注意,包含所要初始化物件的 sizeof 運算式並不等於其本身的參考,但在 C 和 C++ 中都是允許的。

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

  • 在 Windows Vista 以前的 Windows 作業系統上,__declspec( thread ) 會有一些限制。 DLL 如果將任何資料或物件宣告成 __declspec( thread ),則動態載入它可能會造成保護錯誤。 在以 LoadLibrary 載入 DLL 後,每當程式碼參考 __declspec( thread ) 資料,就會造成系統錯誤。 因為執行緒的全域變數空間是在執行階段配置,這個空間的大小是根據應用程式的需求加上所有靜態連結的 DLL 的需求計算而來。 當您使用 LoadLibrary 時,就無法擴充這個空間來接納使用 __declspec( thread ) 所宣告的執行緒區域變數。 如果您可能會使用 LoadLibrary 載入 DLL,請在 DLL 中使用 TLS API (例如,TlsAlloc) 來配置 TLS。

請參閱

概念

執行緒區域儲存區