Delen via


Lokale opslag van threads (TLS)

Tls (Thread Local Storage) is de methode waarmee elke thread in een bepaald multithreaded-proces locaties kan toewijzen waar threadspecifieke gegevens moeten worden opgeslagen. Dynamisch gebonden threadspecifieke gegevens (runtime) worden ondersteund door middel van de TLS-API (TlsAlloc). Win32 en de Microsoft C++-compiler ondersteunen nu naast de bestaande API-implementatie ook per-thread gegevens die statisch gebonden worden bij laadtijd.

Compiler-implementatie voor TLS

C++11: De thread_local aanduiding van de opslagklasse is de aanbevolen manier om thread-lokale opslag op te geven voor objecten en klasseleden. Zie Opslagklassen (C++) voor meer informatie.

MSVC biedt ook een Microsoft-specifiek kenmerk, thread, als uitgebreide wijzigingsfunctie voor opslagklassen. Gebruik het __declspec trefwoord om een thread variabele te declareren. Met de volgende code wordt bijvoorbeeld een geheel getal dat lokaal is voor een thread gedefinieerd en geïnitialiseerd met een waarde.

__declspec( thread ) int tls_i = 1;

Regels en beperkingen

De volgende richtlijnen moeten worden waargenomen bij het declareren van lokale objecten en variabelen voor statische threads. Deze richtlijnen zijn zowel van toepassing op threads als op thread_local:

  • Het thread kenmerk kan alleen worden toegepast op klasse- en gegevensdeclaraties en -definities. Het kan niet worden gebruikt voor functiedeclaraties of definities. Met de volgende code wordt bijvoorbeeld een compilerfout gegenereerd:

    __declspec( thread )void func();     // This will generate an error.
    
  • De thread wijzigingsfunctie kan alleen worden opgegeven voor gegevensitems met static een omvang. Dit omvat globale gegevensobjecten (zowel static als externlokale statische objecten) en statische gegevensleden van C++-klassen. Automatische gegevensobjecten kunnen niet worden gedeclareerd met het thread kenmerk. Met de volgende code worden compilerfouten gegenereerd:

    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;
    }
    
  • De declaraties en de definitie van een lokaal threadobject moeten allemaal het thread kenmerk opgeven. Met de volgende code wordt bijvoorbeeld een fout gegenereerd:

    #define Thread  __declspec( thread )
    extern int tls_i;        // This will generate an error, since the
    int __declspec( thread )tls_i;        // declaration and definition differ.
    
  • Het thread kenmerk kan niet worden gebruikt als een typeaanpassingsfunctie. Met de volgende code wordt bijvoorbeeld een compilerfout gegenereerd:

    char __declspec( thread ) *ch;        // Error
    
  • Omdat de declaratie van C++-objecten die gebruikmaken van het thread kenmerk is toegestaan, zijn de volgende twee voorbeelden semantisch gelijkwaardig:

    __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.
    
  • Het adres van een lokaal threadobject wordt niet beschouwd als constante en elke expressie met een dergelijk adres wordt niet beschouwd als een constante expressie. In standaard C is het effect om het gebruik van het adres van een lokale threadvariabele als initialisatiefunctie voor een object of aanwijzer te weigeren. De volgende code wordt bijvoorbeeld gemarkeerd als een fout door de C-compiler:

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

    Deze beperking is niet van toepassing in C++. Omdat C++ dynamische initialisatie van alle objecten toestaat, kunt u een object initialiseren met behulp van een expressie die gebruikmaakt van het adres van een lokale threadvariabele. Het wordt net als de constructie van lokale threadobjecten gedaan. De code die eerder wordt weergegeven, genereert bijvoorbeeld geen fout wanneer deze is gecompileerd als een C++-bronbestand. Het adres van een lokale threadvariabele is alleen geldig zolang de thread waarin het adres is genomen nog steeds bestaat.

  • Standaard C maakt het mogelijk om een object of variabele te initialiseren met een expressie die een verwijzing naar zichzelf omvat, maar alleen voor objecten van niet-statische omvang. Hoewel C++ over het algemeen een dergelijke dynamische initialisatie van objecten met een expressie met een verwijzing naar zichzelf toestaat, is dit type initialisatie niet toegestaan met lokale threadobjecten. Voorbeeld:

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

    Een sizeof expressie met het object dat wordt geïnitialiseerd, vertegenwoordigt geen verwijzing naar zichzelf en is ingeschakeld in zowel C als C++.

    C++ staat dergelijke dynamische initialisatie van threadgegevens niet toe vanwege mogelijke toekomstige verbeteringen aan de lokale opslagfaciliteit voor threads.

  • Op Windows-besturingssystemen voor Windows Vista gelden __declspec( thread ) enkele beperkingen. Als een DLL gegevens of objecten __declspec( thread )als declareert, kan dit een beveiligingsfout veroorzaken als deze dynamisch wordt geladen. Nadat het DLL-bestand is geladen met LoadLibrary, veroorzaakt het systeemfouten wanneer de code verwijst naar de __declspec( thread ) gegevens. Omdat de globale variabele ruimte voor een thread tijdens runtime wordt toegewezen, is de grootte van deze ruimte gebaseerd op een berekening van de vereisten van de toepassing plus de vereisten van alle DLL's die statisch zijn gekoppeld. Wanneer u deze ruimte gebruikt LoadLibrary, kunt u deze ruimte niet uitbreiden om lokale threadvariabelen toe te staan die zijn gedeclareerd met __declspec( thread ). Gebruik de TLS-API's, zoals TlsAlloc, in uw DLL om TLS toe te wijzen als het DLL-bestand mogelijk wordt geladen met LoadLibrary.

Zie ook

Multithreading met C en Win32