TLS(Thread Local Storage) : __thread 키워드를 이용한 thread 별 독립적 변수

여러분은 C 나 C++ 프로그래밍을 할 때 errno 에 대해 고민해보신 적 있으신가요?

errno 는 과연 thread safe 할까 아닐까?
다수의 thread 에서 errno 값을 마구 변경해대면 다른 thread 에서 보게 되는 errno 에도 영향이 있는 것 아닌가?
thread A 가 특정 함수호출에서 에러가 발생하여 errno 값이 설정되었는데, 공교롭게도 다른 thread B 가 또 다른 에러를 발생시켰을 때 이 값이 짧은 시간에 변경이 되어 결국 thread A 는 B 가 셋팅한 errno 값을 보게 되는 경우는 없을까 ?

이런 고민 안해보셨나요 ? ^^

결론적으로 말하면 POSIX Thread는 기본적으로 errno에 대한 스레드 세이프를 보장합니다.
다른 유닉스운영체제로의 포팅을 염두에 둔다면, gcc 컴파일 옵션에 -D_REENTRANT (Solaris), -D_THREAD_SAFE (AIX)를 명시해야 합니다.

그렇다면, 이러한 errno 는 어떻게 thread safe 를 보장하는 것일까요 ?

이는 TLS(Thread Local Storage)라는 것이 존재하기 때문입니다. 즉, 모든 thread 가 동일한 이름의 변수를 사용해도 실제로는 각 thread 마다 독립적인 공간에 변수값을 저장하는 방식을 말합니다.

gcc 에서는 이 방식을 지원하기 위해 __thread 라는 키워드를 사용합니다.

변수를 선언 시에 __thread int var; 와 같이 사용하면 됩니다.
만약 아래와 같이 global 변수와 TLS 변수를 선언하면 둘의 의미는 완전히 다른 것이죠.

int global;
__thread int tls;

global 변수는 프로세스 내의 모든 thread 가 공유하는 변수이기 때문에 한 놈이 변경하면 그 값이 다른 놈에게도 똑같이 적용됩니다.
하지만, tls 변수는 하나의 thread 가 값을 변경하면 해당 thread 에게만 적용이 될 뿐 다른 thread 가 보는 tls 변수값은 원래 자신이 유지하고 있던 그대로가 됩니다.

이를 사용하는 예제는 pthread 프로그램을 간단히 작성해서 여러분이 한번 확인해 보세요.

주의할 점은 이러한 TLS 변수는 아무 시스템에서나 사용할 수 있는 것은 아니고, Linux Kernel 2.6 + gcc 3.3 + glibc 2.3 + NPTL(Native Posix Thread Library) 환경 하에서만 활용할 수 있습니다.
그리고, TLS 를 내부적으로 구현하기 위해서는 여분의 레지스터가 필요하기 때문에, x86 등의 아키텍쳐에서는 구현이 되어 있지만 MIPS 에서는 구현할 수 없다고 합니다.

You may also like...

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x