web-dev-qa-db-ja.com

gccの「__thread」はどのように機能しますか?

Gccの__threadはどのように実装されていますか? pthread_getspecificpthread_setspecificの単なるラッパーですか?

TLSにposix APIを使用する私のプログラムでは、プログラムランタイムの30%がpthread_getspecificに費やされていることに少しがっかりしています。リソースを必要とする各関数呼び出しのエントリで呼び出しました。コンパイラーは、最適化をインライン化した後、pthread_getspecificを最適化しないようです。したがって、関数がインライン化された後、コードは基本的に正しいTLSポインターを繰り返し検索して、同じポインターを返します。

__threadはこの状況で助けてくれますか? C11にはthread_localがあることは知っていますが、私が持っているgccはまだサポートしていません。 (しかし、私のgccはマクロではなく_Thread_localをサポートしていることがわかりました。)

簡単にテストして確認できることを知っています。しかし、私は今どこかに行かなければなりません、そして、私はかなり大きな書き直しを試みる前に、機能についてよりよく知りたいです。

21
xiver77

最近の [〜#〜] gcc [〜#〜] 、例: GCC 5 C11とそのthread_localをサポートします(たとえば、gcc -std=c11でコンパイルする場合)。 FUZxxl がコメントされているため、(C11 thread_localの代わりに)古いGCCバージョンでサポートされている__thread修飾子を使用できます。 スレッドローカルストレージ についてお読みください。

pthread_getspecificは非常に遅い(POSIXライブラリにあるため、GCCでは提供されないが、たとえば GNU glibc または musl-libc )関数呼び出し。 thread_local変数を使用すると、おそらくより高速になります。

実装例については、 MUSLのthread/pthread_getspecific.cファイル のソースコードをご覧ください。関連する質問の この回答 を読んでください。

_threadthread_localは、(多くの場合)pthread_getspecificの呼び出しに魔法のように変換されません。通常、これらには特定のアドレスモードやレジスタが含まれます(詳細は [〜#〜] abi [〜#〜] ;に関連する実装固有です。Linuxでは、x86-64にはより多くのレジスタとアドレスモード、TLSの実装はi386よりも高速です) コンパイラリンカー および ランタイムシステム 。反対に、pthread_getspecificの一部の実装が(POSIXスレッドの実装で)内部thread_local変数を使用していることがあります。

例として、次のコードをコンパイルします

#include <pthread.h>

const extern pthread_key_t key;

__thread int data;

int
get_data (void) {
  return data;
}

int
get_by_key (void) {
  return *(int*) (pthread_getspecific (key));
}

gCC 5.2(Debian/Sid)でgcc -m32 -S -O2 -fverbose-asmを使用すると、TLSを使用してget_dataに次のコードが提供されます。

  .type get_data, @function
get_data:
.LFB3:
  .cfi_startproc
  movl  %gs:data@ntpoff, %eax   # data,
  ret
.cfi_endproc

およびget_by_keyへの明示的な呼び出しを伴うpthread_getspecificの次のコード:

get_by_key:
 .LFB4:
  .cfi_startproc
  subl  $24, %esp   #,
  .cfi_def_cfa_offset 28
  pushl key # key
  .cfi_def_cfa_offset 32
  call  pthread_getspecific #
  movl  (%eax), %eax    # MEM[(int *)_4], MEM[(int *)_4]
  addl  $28, %esp   #,
  .cfi_def_cfa_offset 4
  ret
  .cfi_endproc

したがって、__thread(またはC11のthread_local)でTLSを使用する方が、pthread_getspecificを使用する(呼び出しのオーバーヘッドを回避する)よりもおそらく高速です。

thread_local<threads.h>で定義された便利なマクロ (C11標準ヘッダー)であることに注意してください。

13

gccの__threadは、C11の_Thread_localとまったく同じ意味を持ちます。実装の詳細はプラットフォーム間で異なるため、プログラミング対象のプラットフォームを教えてはいけません。たとえば、x86 Linuxでは、gccは%fsを呼び出す代わりに、pthread_getspecificセグメントプレフィックスを持つメモリ命令としてスレッドローカル変数へのアクセスをコンパイルする必要があります。

4
fuz