TLS

TLS(스레드 로컬 스토리지)는 지정된 다중 스레드 프로세스의 각 스레드에서 스레드별 데이터를 저장하는 위치를 할당하는 방법입니다. 동적으로 바인딩된(런타임) 스레드별 데이터는 TLS API(TlsAlloc)를 통해 지원됩니다. Win32 및 Microsoft C++ 컴파일러는 이제 기존 API 구현 외에도 스레드당 정적으로 바인딩된(로드 시간) 데이터를 지원합니다.

TLS용 컴파일러 구현

C++11:thread_local 스토리지 클래스 지정자는 개체 및 클래스 멤버에 대한 스레드 로컬 스토리지를 지정하는 권장 방법입니다. 자세한 내용은 Storage 클래스(C++)를 참조하세요.

MSVC는 확장 스토리지 클래스 한정자로 Microsoft 특정 특성인 스레드도 제공합니다. __declspec 키워드(keyword) 사용하여 변수를 선언합니다thread. 예를 들어, 다음 코드는 정수 스레드 로컬 변수를 선언한 다음 값으로 초기화합니다.

__declspec( thread ) int tls_i = 1;

규칙 및 제한 사항

정적으로 바인딩된 스레드 로컬 개체 및 변수를 선언할 때는 다음 지침을 준수해야 합니다. 이러한 지침은 스레드thread_local 모두에 적용됩니다.

  • 특성은 thread 클래스 및 데이터 선언 및 정의에만 적용할 수 있습니다. 함수 선언 또는 정의에는 사용할 수 없습니다. 예를 들어, 다음 코드는 컴파일러 오류를 생성합니다.

    __declspec( thread )void func();     // This will generate an error.
    
  • thread 정자는 익스텐트 데이터 항목 static 에만 지정할 수 있습니다. 여기에는 전역 데이터 개체(및 staticextern), 로컬 정적 개체 및 C++ 클래스의 정적 데이터 멤버가 포함됩니다. 특성으로 thread 자동 데이터 개체를 선언할 수 없습니다. 다음 코드는 컴파일러 오류를 생성합니다.

    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;
    }
    
  • 스레드 로컬 개체의 선언 및 정의는 모두 특성을 지정 thread 해야 합니다. 예를 들어, 다음 코드는 오류를 생성합니다.

    #define Thread  __declspec( thread )
    extern int tls_i;        // This will generate an error, since the
    int __declspec( thread )tls_i;        // declaration and definition differ.
    
  • thread 특성을 형식 한정자로 사용할 수 없습니다. 예를 들어, 다음 코드는 컴파일러 오류를 생성합니다.

    char __declspec( thread ) *ch;        // Error
    
  • 특성을 사용하는 thread C++ 개체의 선언이 허용되므로 다음 두 예제는 의미상 동일합니다.

    __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.
    
  • 스레드 로컬 개체의 주소는 상수로 간주되지 않으며 이러한 주소와 관련된 식은 상수 식으로 간주되지 않습니다. 표준 C에서는 스레드 지역 변수의 주소를 개체 또는 포인터의 이니셜라이저로 사용할 수 없습니다. 예를 들어 다음 코드는 C 컴파일러에서 오류로 플래그 지정됩니다.

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

    이 제한은 C++에서 적용되지 않습니다. C++에서는 모든 개체의 동적 초기화가 허용되기 때문에, 스레드 로컬 변수의 주소를 사용하는 식을 사용하여 개체를 초기화할 수 있습니다. 스레드 로컬 개체의 생성과 마찬가지로 수행됩니다. 예를 들어 앞서 표시된 코드는 C++ 소스 파일로 컴파일될 때 오류를 생성하지 않습니다. 스레드 로컬 변수의 주소는 주소를 가져온 스레드가 여전히 존재하는 한 유효합니다.

  • 표준 C에서는 자체에 대한 참조를 포함하는 식을 사용하여 개체 또는 변수를 초기화할 수 있지만 비정적 익스텐트 개체에만 사용할 수 있습니다. C++는 일반적으로 자체에 대한 참조를 포함하는 식을 사용하여 개체를 동적으로 초기화할 수 있지만 이러한 종류의 초기화는 스레드 로컬 개체에서 허용되지 않습니다. 예시:

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

    sizeof 초기화되는 개체를 포함하는 식은 자체에 대한 참조를 나타내지 않으며 C 및 C++에서 모두 사용하도록 설정됩니다.

    C++는 스레드 로컬 스토리지 기능에 대한 향후 향상된 기능으로 인해 스레드 데이터의 동적 초기화를 허용하지 않습니다.

  • Windows Vista 이전의 Windows 운영 체제에는 __declspec( thread ) 몇 가지 제한 사항이 있습니다. DLL이 데이터 또는 개체를 선언하는 경우 동적으로 __declspec( thread )로드되는 경우 보호 오류가 발생할 수 있습니다. LoadLibrary를 사용하여 DLL을 로드한 후 코드에서 데이터를 참조할 때마다 시스템 오류가 발생합니다__declspec( thread ). 런타임에 스레드에 대한 전역 변수 공간이 할당되기 때문에, 이 공간의 크기는 애플리케이션의 요구 사항과 정적으로 연결되는 모든 DLL의 요구 사항을 계산하여 결정됩니다. 사용하는 LoadLibrary경우 이 공간을 확장하여 로 선언된 __declspec( thread )스레드 지역 변수를 허용할 수 없습니다. DLL이 로드될 수 있는 경우 DLL에서 TLS API(예: TlsAlloc)를 사용하여 TLS를 LoadLibrary할당합니다.

참고 항목

C 및 Win32를 사용한 다중 스레딩