'thread local storage'에 해당되는 글 1건

  1. 2012.02.20 TLS, Thread-Local Storage
프로그래밍2012. 2. 20. 16:23
출처:

[1] http://en.wikipedia.org/wiki/Thread-local_storage

[2] http://november11.tistory.com/entry/TLSThread-Local-Storage

[4] http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Thread-Local.html

[3] http://sian999.egloos.com/3945779


TLS는 static혹은 global 메모리를 쓰레드에 지역적으로 쓸 수 있게 하는 프로그래밍 메소드다.

쓰레드는 일반적으로 같은 프로세스 안에서 같은 주소 공간(address space)를 사용하기 마련인데, 가끔은 이런걸 원치 않을 때가 있다.  같은 주소 공간을 사용한다는 뜻은 곧 같은 프로세스안의 쓰레드들이 접근할 때, 정적 혹은 전역 변수들이 같은 메모리 location에 있다는 말이다  이와 반대로, 스택에 있는 변수들은 각 쓰레드들에게 지역적(local)이다.(쓰레드는 각각의 스택을 지니고 있으므로 당연하다)

예를 들어, 두개 이상의 쓰레드가, 같은 정적 혹은 전역 변수를 접근할 때, 실제로는 다른 메모리 location을 접근하도록 하고 싶을 때가 있을 것이다.(즉 정적/전역변수를 로컬화 한다는 소리) 이런한 경우의 클래식 적인 예가 errno가 되겠다.


TLS를 사용하는 방법에는 2가지가 있는데, 

  1. 한가지는 정적으로 compiler 타임에 사용하는 것이고,

  2. 다른 하나는 동적으로 API를 사용하는 것이다.


우선 정적인 경우를 보자.

[3]비쥬얼 C++ 컴파일러 기준으로는 저장소 선언 지정자 __declspen(thread)를 사용한다.  이렇게 해서 변수를 정의하면, 컴파일러가 변수를 .tls라는 이름을 갖는 바이너리 파일의 데이터 영역에 변수를 넣도록 지시한다.  링커는 오브젝트 파일에 있는 모든 .tls 파일을 묶어서 exe나 dll바이너리 안의 .tls 섹션에 위치시킨다.

그러면 운영체제는 바이너리 실행파일이나 dll를 로드할 때, .tls영역에 대해서 주 스레드의 영역에 있는 모든 변수를 담을 수 있을만한 별도의 메모리를 할당하고, 각각의 스레드가 자신을 위해서 특별히 할당된 데이터 블럭만을 접근하도록 보장한다.

문제가 있다면 이렇게 정적으로 할당된 경우, 프로그램이 처음 로드될 때 운영체제가 .tls 메모리 블럭의 크기를 결정해야 한다.  exe파일에 정의된 정적 tls변수와 제한적으로 링크된 dll의 경우 잘 동작하나 loadlibray를 사용해서 로드된 dll은 .tls메모리 블록의 크기를 알기 어려우며, 처음에 생성할때 정해진 tls영역의 크기를 확장할 수 없다.  그래서 애플리케이션에서만 정적 스레드 로컬 저장소를 사용해야 하고 라이브러리는 동적 스레드 로컬 저장소 API를 사용해야만 한다.


[4]GCC의 경우 우선 compiler를 사용하는 방법에는 linker(ld), dynamic linker(ld.so), system libraries(libc.so & libpthread.so)들의 support가 필요하다.

유저 레벨에서의 확장은 __thread라는  새로운 기억 클래스 부류를 사용한다.

예를 들어,

__thread int i;

extern __thread struct state s;

static __thread char *p;

처럼 선언 할수 있다.

__thread는 어떠한 전역변수, 파일스코프 정적, 정적변수 에게나 적용할 수 있으나, 블록 한정 automatic 혹은 non-static 데이터 멤버에게는 적용 할 수 없다.


실제로 위의 코드를 첨가해서 파일을 만든 뒤 readelf -S 로 읽어보면, 

.tbass

.tdata

라는 섹션이 생김을 확인 할 수 있다.


arm 컴파일러에서는 RVCT 3.0에서 TLS를 지원한다고 나와있으며, __declspec(thread)과 __thread라는 2개의 키워드를 지원한다.

이제 동적인 경우를 보자.

MSDN에 따르면, TLS를 구현하기 위한 단계는 다음과 같다.

  1. 프로세스나 dll 초기화 때 TLS 인덱스를 할당하기 위해서 TlsAlloc함수를 사용하라.
  2. TLS인덱스를 사용할 필요가 있는 각 쓰레드를 위해 동적 메모리를 할당하고, TlsSetValue를 사용해서 TLS 인덱스와 방금 할당한 메모리를 연결하라
  3. 쓰레드가 그 자신의 메모리를 접근해야 할 때, TlsGetValue함수를 사용해서 TLS인덱스를 지정해 그 메모리의 포인터를 얻어라
  4. TLS인덱스와 연결된 동적 메모리를 더 이상 사용할 필요가 없을때는 반드시 해제하라.  TLS 인덱스를 사용하는 모든 쓰레다가 종료되면, TlsFree함수를 사용하여 TLS인덱스를 해제하라.








Posted by code cat