Freigeben über


Regeln und Einschränkungen für TLS

Aktualisiert: November 2007

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 darf 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 TLS-Objekts 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 jedoch nicht für C++. Da C++ die dynamische Initialisierung aller Objekte gestattet, kann ein Objekt mit einem Ausdruck initialisiert werden, der die Adresse einer TLS-Variablen verwendet. Die Vorgehensweise ist hierbei identisch mit der Konstruktion eines TLS-Objekts. Durch den oben aufgeführten Code wird z. B. kein Fehler verursacht, wenn der 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 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 TLS-Objekte nicht zutreffend. Beispiel:

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

  • Wenn durch eine DLL beliebige nicht lokale 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 nicht lokalen __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 gibt es keine Möglichkeit, diesen Speicher für die TLS-Variablen, die mit __declspec( thread ) deklariert wurden, zu erweitern. Wenn die Möglichkeit besteht, dass die DLL mit LoadLibrary geladen wird, verwenden Sie zur Zuweisung von TLS die TLS-APIs, z. B. TlsAlloc.

Siehe auch

Konzepte

Lokaler Threadspeicher (TLS)