Regeln und Einschränkungen für TLS

Die folgenden Richtlinien müssen bei der Deklaration von statisch gebundenen TLS-Objekten und -variablen beachtet werden:

  • Das thread-Attribut kann nur auf Datendeklarationen und -definitionen angewendet werden.Die Verwendung in Funktionsdeklarationen oder -definitionen ist nicht zulässig.Beispielsweise verursacht der folgende Code einen Compilerfehler:

    #define Thread  __declspec( thread )
    Thread void func();     // This will generate an error.
    
  • Der thread-Modifizierer kann nur in Datenelementen mit static-Extent angegeben werden.Hierzu zählen globale Datenobjekte (sowohl static als auch extern), lokale statische Objekte sowie statische Datenmember von C++-Klassen.Automatische Datenobjekte können nicht mit dem thread-Attribut deklariert werden.Im folgenden Code werden Compilerfehler generiert:

    #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;
    }
    
  • In allen Deklaration und Definitionen eines lokalen Threadobjekts muss das thread-Attribut angegeben werden.Durch folgenden Code wird z. B. ein Fehler verursacht:

    #define Thread  __declspec( thread )
    extern int tls_i;        // This will generate an error, since the
    int Thread tls_i;        // declaration and definition differ.
    
  • Das thread-Attribut kann nicht als Typmodifizierer verwendet werden.Beispielsweise verursacht der folgende Code einen Compilerfehler:

    char __declspec( thread ) *ch;        // Error
    
  • Das thread-Attribut kann nicht von C++-Klassen verwendet werden.C++-Klassenobjekte können jedoch mit dem thread-Attribut instanziiert werden.Beispielsweise verursacht der folgende Code einen Compilerfehler:

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

    Da die Deklaration von C++-Objekten, die das thread-Attribut verwenden, zulässig ist, ist die Semantik der beiden folgenden Beispiele gleichwertig:

    #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.
    
  • Die Adresse eines TLS-Objekts wird nicht als konstant angesehen und jeder Ausdruck mit einer solchen Adresse nicht als konstanter Ausdruck.In Standard-C bedeutet dies, dass die Verwendung der Adresse einer TLS-Variablen als Initialisierer für ein Objekt oder einen Zeiger nicht zulässig ist.Folgender Code wird z. B. vom C-Compiler mit einem Fehlerflag versehen:

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

    Diese Einschränkung gilt nicht für C++.Da C++ die dynamische Initialisierung aller Objekte gestattet, kann ein Objekt mit einem Ausdruck initialisiert werden, der die Adresse einer lokalen Threadvariablen verwendet.Die Vorgehensweise ist hierbei identisch mit der Konstruktion eines lokalen Threadobjekts.Durch den zuvor aufgeführten Code wird z. B. kein Fehler generiert, wenn er als C++-Quelldatei kompiliert wird.Beachten Sie, dass die Adresse einer TLS-Variablen nur solange gültig ist, solange der Thread vorhanden ist, aus dem die jeweilige Adresse stammt.

  • In Standard-C ist die Initialisierung eines Objekts oder einer Variablen mit einem Ausdruck zulässig, der einen Verweis auf sich selbst enthält. Dies gilt jedoch nur für Objekte, die keinen static-Extent aufweisen.Obwohl in C++ diese Art der dynamischen Initialisierung von Objekten mit einem Ausdruck, der einen Verweis auf sich selbst enthält, normalerweise zulässig ist, ist dies für lokale Threadobjekte nicht zutreffend.Beispiele:

    #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++
    

    Beachten Sie, dass ein sizeof-Ausdruck, der das Objekt enthält, das derzeit initialisiert wird, keinen Verweis auf sich selbst darstellt und sowohl in C als auch in C++ gültig ist.

    In C++ ist diese Art der dynamischen Initialisierung von Threaddaten aufgrund möglicher zukünftiger Verbesserungen der TLS-Funktion nicht zulässig.

  • Unter Windows-Betriebssystemen vor Windows Vista weist __declspec (Thread) einige Einschränkungen auf.Wenn durch eine DLL beliebige Daten oder Objekte als __declspec( thread ) deklariert werden, kann beim dynamischen Ladevorgang eine allgemeine Schutzverletzung auftreten.Nachdem die DLL mit LoadLibrary geladen wurde, tritt bei jedem Verweis des Codes auf die __declspec( thread )-Daten ein Systemfehler auf.Da der globale Variablenspeicher für einen Thread zur Laufzeit reserviert wird, basiert die Größe dieses Speichers auf der Berechnung der Anforderungen der jeweiligen Anwendung sowie der Anforderungen aller DLLs, die statisch gebunden sind.Bei der Verwendung von LoadLibrary können Sie diesen Speicher nicht für die lokalen Threadvariablen erweitern, die mit __declspec( Thread ) deklariert wurden.Wenn die Möglichkeit besteht, dass die DLL mit LoadLibrary geladen wird, verwenden Sie zur Zuweisung von TLS die TLS-APIs in der DLL, z. B. TlsAlloc.

Siehe auch

Konzepte

Lokaler Threadspeicher (TLS)