쓰레드별 변수 __thread 사용

Posted at 2009/04/09 13:53 // in Programming // by Daniel

OS가 지원해야 하며 일단 제가 알기로는 Linux(2.6부터) gcc와 MSVC에서 지원되는데요,

TLS - Thread Local Storage 라고 불립니다. 시스템콜로 구현되는 것 같더군요.

일단 구현된 내용은 차치하고 사용법은 다음과 같습니다.

 

gcc의 경우만 설명

__thread int my_thread_var;
static __thread int my_static_thread_var;

 

__thread 키워드로 구분되며 이렇게 선언한 변수는 쓰레드마다 가지게 됩니다.

 

관련 내용 링크

Linux 2.6 속으로!

... 또 다른 변화는 TLS (Thread Local Storage) 시스템 호출의 도입이다. 쓰레드 레지스터로 사용될 수 있는 GDT (Global Descriptor Table) 엔트리를 한 개 이상 할당 할 수 있다. GDT는 CPU 기반이고 엔트리는 쓰레드 기반이다.

TLS - Thread Local Storage http://purewell.egloos.com/3398289

* GCC 메뉴얼 보면 TLS가 아니라 TSD(Thread Storage Duration)이라고 표현하였는데 대충 같은 말이다.
이것을 위해 POSIX는 pthread_key_create, pthread_get/setspecific 등 함수를 마련해놨지만 눈만 팽글팽글 돌고, 소스만 지저분해져 보일 것 같다. 귀찮으면 C99, C++98 표준 __thread 키워드를 사용하자.

http://kldp.org/node/78262

~$ /lib/libc.so.6
...
Thread-local storage support included. << 이부분이 보인다면 현재 glibc가 TLS를 지원하는버젼입니다.

크리에이티브 커먼즈 라이센스
Creative Commons License

__builtin_expect 키워드

Posted at 2009/04/01 22:08 // in Programming // by Daniel

재밌는 컴파일러 키워드 __builtin_expect

gcc에서만 일단 사용이 가능하지만 한가지 흥미있는 키워드를 발견했다. __builtin_expect 라는 키워드다 다음과 같이 사용할 수 있다.

void* p = malloc(100);

// if (p == NULL)
// error();

if (__builtin_expect(p == NULL, 0))
error();

위와 같은 경우는 아주 많이 접할 것이다. 그런데 사실 포인터 p가 NULL인 경우는 잘 없다. 99.99%는 항상 p != NULL가 될 것이다. 이럴 경우 __builtin_expect는 매우 유용하게 사용할 수 있다.
이 키워드는 p == NULL의 값이 *대부분* false가 될 것이 라고 컴파일러에게 알려준다. 그래서 CPU가 좀 더 효율적으로 명령어를 fetch할 수 있도록 한다. 물론 그렇다고해서 프로그램의 정확성, 즉 p가 NULL이면 error가 실행되라는 것까지 해치지는 않는다. 단순히 프로그램의 성능 향상을 위한 키워드이다.

pthread 소스 보면서 찾았네요.

pthread_mutex_lock 소스가 상당히 기네요..

glibc-2.7/nptl/pthread_mutex_lock.c

int
__pthread_mutex_lock (mutex)
     pthread_mutex_t *mutex;
{
  assert (sizeof (mutex->__size) >= sizeof (mutex->__data));
  int oldval;
  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
  int retval = 0;
  switch (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex),
                PTHREAD_MUTEX_TIMED_NP))
    {
      /* Recursive mutex.  */
    case PTHREAD_MUTEX_RECURSIVE_NP:
      /* Check whether we already hold the mutex.  */
      if (mutex->__data.__owner == id)
    {
      /* Just bump the counter.  */
      if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
        /* Overflow of the counter.  */
        return EAGAIN;
      ++mutex->__data.__count;
      return 0;
    }
      /* We have to get the mutex.  */
      LLL_MUTEX_LOCK (mutex);
      assert (mutex->__data.__owner == 0);
      mutex->__data.__count = 1;
      break;
      /* Error checking mutex.  */
    case PTHREAD_MUTEX_ERRORCHECK_NP:
      /* Check whether we already hold the mutex.  */
      if (__builtin_expect (mutex->__data.__owner == id, 0))
    return EDEADLK;
      /* FALLTHROUGH */

.......

 

이게 LinuxThreads와 NPTL의 소스가 다 있어서 한참을 검색했는데

이렇게 하면 나오네요. NPTL을 쓰는군요

$ /lib/libpthread.so.0
Native POSIX Threads Library by Ulrich Drepper et al
Copyright (C) 2006 Free Software Foundation, Inc.

 

데비안에서 소스 받기는

$ dpkg-query -S /lib/libpthread.so.0
libc6: /lib/libpthread.so.0
이렇게 찾고


$ apt-get source libc6
이렇게 받습니다.
압축은 푸셔야 되구요. -b 로 빌드도 같이 되게 할 수 있지만 의존성 때매 실패할겁니다

크리에이티브 커먼즈 라이센스
Creative Commons License