TLS 규칙 및 제한

정적으로 바인딩된 스레드 지역 개체 및 변수를 선언하는 경우 다음과 같은 지침을 준수해야 합니다.

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

    #define Thread  __declspec( thread )
    Thread void func();     // This will generate an error.
    
  • thread 한정자는 static 범위를 사용하는 데이터 항목에만 지정할 수 있습니다. 여기에는 전역 데이터 개체(static 및 extern), 지역 정적 개체 및 C++ 클래스의 정적 데이터 멤버가 포함됩니다. 자동 데이터 개체는 thread 특성을 사용하여 선언할 수 없습니다. 다음 코드에서는 컴파일러 오류가 생성됩니다.

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

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

    char __declspec( thread ) *ch;        // Error
    
  • C++ 클래스는 thread 특성을 사용할 수 없습니다. 그러나 C++ 클래스 개체는 thread 특성을 사용하여 인스턴스화할 수 있습니다. 예를 들어, 다음 코드는 컴파일러 오류를 생성합니다.

    #define Thread  __declspec( thread )
    class Thread C       // Error: classes cannot be declared Thread.
    {
    // Code
    };
    C CObject;
    

    thread 특성을 사용하는 C++ 개체를 선언할 수 있으므로 다음 두 예제는 같은 의미입니다.

    #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.
    
  • 스레드 지역 개체의 주소는 상수로 간주되지 않으므로 이 주소를 포함하는 모든 식은 상수 식으로 간주되지 않습니다. 표준 C에서 이것은 스레드 지역 변수의 주소를 개체 또는 포인터의 초기 값으로 사용할 수 없음을 의미합니다. 예를 들어, 다음 코드는 C 컴파일러에서 오류로 간주됩니다.

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

    C++에서는 이러한 제한이 적용되지 않습니다. C++에서는 모든 개체를 동적으로 초기화할 수 있으므로 스레드 지역 변수의 주소를 사용하는 식으로 개체를 초기화할 수 있습니다. 이 작업은 스레드 지역 개체 생성과 동일한 방식으로 수행됩니다. 예를 들어, 앞의 코드는 C++ 소스 파일로 컴파일할 경우 오류를 생성하지 않습니다. 스레드 지역 변수의 주소는 주소를 사용하는 스레드가 있는 경우에만 유효합니다.

  • 표준 C에서는 비 정적 범위의 개체에 한해 자신에 대한 참조를 포함하는 식으로 개체 또는 변수를 초기화할 수 있습니다. C++는 일반적으로 자신에 대한 참조를 포함하는 식에서 개체의 동적 초기화를 허용하지만 스레드 지역 개체에 대해서는 이러한 종류의 초기화를 허용하지 않습니다. 예를 들면 다음과 같습니다.

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

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

    앞으로 스레드 로컬 저장소 기능이 향상될 수 있으므로 C++는 스레드 데이터의 동적 초기화를 허용하지 않습니다.

  • Windows Vista 이전의 Windows 운영 체제에서는 __declspec(스레드)에 일부 제한이 있습니다. DLL에서 데이터 또는 개체를 __declspec(스레드)로 선언하는 경우 동적으로 로드되면 보호 결함이 발생할 수 있습니다. LoadLibrary로 DLL이 로드된 다음 코드에서 __declspec(스레드) 데이터를 참조할 때마다 시스템 오류가 발생합니다. 스레드의 전역 변수 공간은 런타임에서 할당되므로 이 공간의 크기는 응용 프로그램의 요구 사항과 정적으로 링크된 모든 DLL의 요구 사항을 더한 값을 기반으로 합니다. LoadLibrary를 사용하는 경우 __declspec(스레드)로 선언된 스레드 지역 변수를 허용할 만큼 이 공간을 확장할 수 없습니다. LoadLibrary를 사용하여 DLL을 로드하는 경우 TLS를 할당하려면 DLL에서 TLS API(예: TlsAlloc)를 사용하십시오.

참고 항목

개념

TLS