Sdílet prostřednictvím


Lokální úložiště vláken (TLS)

Místní úložiště vlákna (TLS) je metoda, podle které každé vlákno v daném vícevláknovém procesu může přidělit umístění, ve kterých se mají ukládat data specifická pro vlákna. Dynamicky svázaná data specifická pro vlákna (run-time) se podporují prostřednictvím rozhraní TLS API (TlsAlloc). Win32 a kompilátor Microsoft C++ teď kromě stávající implementace rozhraní API podporují staticky svázaná data (doba načítání) pro každé vlákno.

Implementace kompilátoru pro protokol TLS

C++11: Specifikátor thread_local třídy úložiště je doporučený způsob, jak určit místní úložiště vláken pro objekty a členy třídy. Další informace najdete v tématu Třídy úložiště (C++).

MSVC také poskytuje atribut specifický pro Microsoft, vlákno, jako modifikátor rozšířené třídy úložiště. Pomocí klíčového __declspec slova deklarujte proměnnou thread . Například následující kód deklaruje místní proměnnou celočíselného vlákna a inicializuje ji hodnotou:

__declspec( thread ) int tls_i = 1;

Pravidla a omezení

Při deklarování staticky vázaného vlákna místních objektů a proměnných musí být pozorovány následující pokyny. Tyto pokyny platí pro vlákno i pro thread_local:

  • Atribut thread lze použít pouze u deklarací tříd a dat a definic. Nedá se použít u deklarací funkcí ani definic. Například následující kód vygeneruje chybu kompilátoru:

    __declspec( thread )void func();     // This will generate an error.
    
  • thread Modifikátor lze zadat pouze u datových položek s rozsahemstatic. To zahrnuje globální datové objekty (a static extern), místní statické objekty a statické datové členy tříd jazyka C++. Automatické datové objekty nelze deklarovat pomocí atributu thread . Následující kód generuje chyby kompilátoru:

    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;
    }
    
  • Deklarace a definice místního objektu vlákna musí všechny specifikovat thread atribut. Například následující kód vygeneruje chybu:

    #define Thread  __declspec( thread )
    extern int tls_i;        // This will generate an error, since the
    int __declspec( thread )tls_i;        // declaration and definition differ.
    
  • Atribut thread nelze použít jako modifikátor typu. Například následující kód vygeneruje chybu kompilátoru:

    char __declspec( thread ) *ch;        // Error
    
  • Vzhledem k tomu, že deklarace objektů jazyka C++, které používají thread atribut, je povolena, jsou následující dva příklady sémanticky ekvivalentní:

    __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.
    
  • Adresa místního objektu vlákna není považována za konstantní a žádný výraz zahrnující takovou adresu se nepovažuje za konstantní výraz. Ve standardním jazyce C je výsledkem zakázání použití adresy místní proměnné vlákna jako inicializátoru objektu nebo ukazatele. Například následující kód je označen jako chyba kompilátoru jazyka C:

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

    Toto omezení neplatí v jazyce C++. Vzhledem k tomu, že jazyk C++ umožňuje dynamickou inicializaci všech objektů, můžete objekt inicializovat pomocí výrazu, který používá adresu místní proměnné vlákna. Dělá se stejně jako konstrukce místních objektů vlákna. Například výše uvedený kód negeneruje chybu, když je zkompilován jako zdrojový soubor C++. Adresa místní proměnné vlákna je platná pouze za předpokladu, že vlákno, ve kterém byla adresa přijata, stále existuje.

  • Standardní jazyk C umožňuje inicializaci objektu nebo proměnné pomocí výrazu, který zahrnuje odkaz na sebe sama, ale pouze pro objekty nestatického rozsahu. I když C++ obecně umožňuje takovou dynamickou inicializaci objektů pomocí výrazu, který zahrnuje odkaz na sebe, tento druh inicializace není povolen s místními objekty vlákna. Příklad:

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

    Výraz sizeof , který obsahuje inicializovaný objekt, nepředstavuje odkaz na sebe a je povolen v jazyce C i C++.

    Jazyk C++ neumožňuje takovou dynamickou inicializaci dat vlákna kvůli možným budoucím vylepšením místního úložiště vlákna.

  • V operačních systémech Windows před Windows Vista __declspec( thread ) má určitá omezení. Pokud knihovna DLL deklaruje jakákoli data nebo objekt jako __declspec( thread ), může způsobit chybu ochrany, pokud je dynamicky načtena. Po načtení knihovny DLL s LoadLibrary způsobí selhání systému pokaždé, když kód odkazuje na __declspec( thread ) data. Vzhledem k tomu, že globální proměnný prostor pro vlákno je přidělen za běhu, velikost tohoto prostoru je založená na výpočtu požadavků aplikace a požadavků všech knihoven DLL, které jsou staticky propojené. Pokud použijete LoadLibrary, nemůžete rozšířit toto místo tak, aby umožňovalo místní proměnné vlákna deklarované pomocí __declspec( thread ). Pomocí rozhraní TLS API, jako je například TlsAlloc, v knihovně DLL přidělte protokol TLS, pokud může být knihovna DLL načtena LoadLibrary.

Viz také

Multithreading s použitím jazyka C a prostředí Win32