TLS(스레드 로컬 스토리지)
TLS(스레드 로컬 스토리지)는 지정된 다중 스레드 프로세스의 각 스레드에서 스레드별 데이터를 저장하는 위치를 할당하는 방법입니다. 동적으로 바인딩된(런타임) 스레드별 데이터는 TLS API(TlsAlloc)를 통해 지원됩니다. Win32 및 Microsoft C++ 컴파일러는 이제 기존 API 구현 외에도 스레드당 정적으로 바인딩된(로드 시간) 데이터를 지원합니다.
TLS용 컴파일러 구현
C++11: thread_local
스토리지 클래스 지정자는 개체 및 클래스 멤버에 대한 스레드 로컬 스토리지를 지정하는 권장 방법입니다. 자세한 내용은 Storage 클래스(C++)를 참조하세요.
MSVC는 확장 스토리지 클래스 한정자로 Microsoft 특정 특성인 스레드도 제공합니다. 키워드를 __declspec
사용하여 변수를 선언합니다 thread
. 예를 들어, 다음 코드는 정수 스레드 로컬 변수를 선언한 다음 값으로 초기화합니다.
__declspec( thread ) int tls_i = 1;
규칙 및 제한 사항
정적으로 바인딩된 스레드 로컬 개체 및 변수를 선언할 때는 다음 지침을 준수해야 합니다. 이러한 지침은 스레드와 thread_local 모두에 적용됩니다.
특성은
thread
클래스 및 데이터 선언 및 정의에만 적용할 수 있습니다. 함수 선언 또는 정의에는 사용할 수 없습니다. 예를 들어, 다음 코드는 컴파일러 오류를 생성합니다.__declspec( thread )void func(); // This will generate an error.
한
thread
정자는 익스텐트 데이터 항목static
에만 지정할 수 있습니다. 여기에는 전역 데이터 개체(및static
extern
), 로컬 정적 개체 및 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
할당합니다.