Szál-lokális tárolás (TLS)

A szál helyi tárolása (TLS) az a módszer, amellyel egy adott többszálas folyamat egyes szálai lefoglalhatják a szálspecifikus adatok tárolására szolgáló helyeket. A dinamikusan kötött (futásidejű) szálspecifikus adatokat a TLS API (TlsAlloc) támogatja. A Win32 és a Microsoft C++ fordító mostantól támogatja a statikusan kötött (betöltési idő) szálonkénti adatokat a meglévő API-implementáció mellett.

Compiler implementáció a TLS-hez

C++11: A thread_local tárosztály-meghatározó az objektumok és osztálytagok szálalapú tárolásának ajánlott módja. További információ: Storage-osztályok (C++).

Az MSVC egy Microsoft-specifikus attribútumot, szálat is biztosít kiterjesztett tárosztály-módosítóként. __declspec A kulcsszóval deklarálhat egy változótthread. Az alábbi kód például egy egész szál helyi változóját deklarálja, és inicializálja egy értékkel:

__declspec( thread ) int tls_i = 1;

Szabályok és korlátozások

A statikusan kötött szál helyi objektumainak és változóinak deklarálásakor az alábbi irányelveket kell betartani. Ezek az irányelvek mind a szálra , mind a thread_local vonatkoznak:

  • Az thread attribútum csak osztály- és adatdeklarációkra és definíciókra alkalmazható. Függvénydeklarációkhoz vagy definíciókhoz nem használható. A következő kód például fordítóhibát okoz:

    __declspec( thread )void func();     // This will generate an error.
    
  • A thread módosító csak a static kiterjedéssel rendelkező adatelemeken adható meg. Ide tartoznak a globális adatobjektumok (static és extern), a helyi statikus objektumok, és a C++ osztályok statikus adattagjai. Az automatikus adatobjektumok nem deklarálhatók az thread attribútummal. A következő kód fordítási hibákat generál:

    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;
    }
    
  • A deklarációknak és a szál helyi objektumának definíciójának mind meg kell adnia az thread attribútumot. A következő kód például hibát okoz:

    #define Thread  __declspec( thread )
    extern int tls_i;        // This will generate an error, since the
    int __declspec( thread )tls_i;        // declaration and definition differ.
    
  • Az thread attribútum nem használható típusmódosítóként. A következő kód például fordítóhibát okoz:

    char __declspec( thread ) *ch;        // Error
    
  • Mivel az attribútumot használó thread C++ objektumok deklarációja engedélyezett, a következő két példa szemantikailag egyenértékű:

    __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.
    
  • A szál helyi objektumának címe nem tekinthető állandónak, és az ilyen címeket tartalmazó kifejezések nem tekinthetők állandó kifejezésnek. A C szabványban az a célja, hogy ne engedélyezze egy szál-lokális változó címének használatát objektum vagy mutató inicializálójaként. A C fordító például a következő kódot jelöli hibaként:

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

    Ez a korlátozás a C++-ban nem érvényes. Mivel a C++ lehetővé teszi az összes objektum dinamikus inicializálását, inicializálhat egy objektumot egy olyan kifejezéssel, amely egy szál helyi változójának címét használja. Ugyanúgy történik, mint a szál helyi objektumainak felépítése. A korábban bemutatott kód például nem okoz hibát, ha C++ forrásfájlként van lefordítva. A szál helyi változójának címe csak addig érvényes, amíg a címmel rendelkező szál továbbra is létezik.

  • A Standard C lehetővé teszi egy objektum vagy változó inicializálását egy olyan kifejezéssel, amely önmagára mutató hivatkozást tartalmaz, de csak nemsztatikus méretű objektumok esetében. Bár a C++ általában lehetővé teszi az objektumok ilyen dinamikus inicializálását olyan kifejezéssel, amely magában foglalja a magára való hivatkozást, az ilyen típusú inicializálás nem engedélyezett a szál helyi objektumaival. Például:

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

    Az sizeof inicializálandó objektumot tartalmazó kifejezés nem önmagára mutató hivatkozást jelent, és c és C++ nyelven is engedélyezve van.

    A C++ nem teszi lehetővé a száladatok ilyen dinamikus inicializálását a szál helyi tároló létesítményének lehetséges jövőbeli fejlesztései miatt.

  • A Windows Vista __declspec( thread ) előtti Windows operációs rendszereken bizonyos korlátozások vonatkoznak. Ha egy DLL bármilyen adatot vagy objektumot __declspec( thread )deklarál, az védelmi hibát okozhat, ha dinamikusan betöltődik. Miután a DLL betöltődött a LoadLibraryval, rendszerhibát okoz, amikor a kód az __declspec( thread ) adatokra hivatkozik. Mivel a szál globális változóterülete futásidőben van lefoglalva, ennek a térnek a mérete az alkalmazás követelményeinek és a statikusan csatolt DLL-ek követelményeinek kiszámításán alapul. Ha használja a LoadLibrary, nem tudja kiterjeszteni ezt a területet, hogy lehetővé tegye a __declspec( thread )-el deklarált szál helyi változókat. A TLS API-kat, például a TlsAlloc-t, használja a DLL-ben a TLS foglalásához, ha a DLL betölthető LoadLibrary.

Lásd még

Többszálúság C és Win32 használatával