C ++がthread_local
言語機能としてストレージを追加しているので、いくつか疑問に思っています。
thead_local
ありそうな 費用はいくらですか?- メモリ内ですか?
- 読み取りおよび書き込み操作の場合?
- これに関連して:オペレーティングシステムは通常どのようにこれを実装しますか?宣言されたものは
thread_local
すべて、作成されたスレッドごとにスレッド固有のストレージスペースを指定する必要があるように思われます。
C ++がthread_local
言語機能としてストレージを追加しているので、いくつか疑問に思っています。
thead_local
ありそうな
費用はいくらですか?thread_local
すべて、作成されたスレッドごとにスレッド固有のストレージスペースを指定する必要があるように思われます。ストレージスペース:変数のサイズ*スレッドの数、または場合によっては(sizeof(var)+ sizeof(var *))*スレッドの数。
スレッドローカルストレージを実装する基本的な方法は2つあります。
現在のカーネルスレッドに関する情報を取得するある種のシステムコールを使用する。Sloooow。
他のすべてのレジスタと同時に、カーネルによってすべてのスレッドコンテキストスイッチで適切に設定された、おそらくプロセッサレジスタ内のポインタを使用します。安いです。
Intelプラットフォームでは、バリアント2は通常、何らかのセグメントレジスタ(FSまたはGS、覚えていません)を介して実装されます。GCCとMSVCの両方がこれをサポートしています。したがって、アクセス時間はグローバル変数の場合とほぼ同じです。
可能ですが、実際にはまだ見ていません。これは、のような既存のライブラリ関数を介して実装されますpthread_getspecific
。その場合、パフォーマンスは1または2のようになり、さらにライブラリ呼び出しのオーバーヘッドが発生します。バリアント2.+ライブラリ呼び出しのオーバーヘッドは、カーネル呼び出しよりもはるかに高速であることに注意してください。
Uli Drepper(glibcのメンテナー)によるLinuxでの動作の説明は、 www.akkadia.org / drepper/ tls.pdfにあります。
動的にロードされるモジュールなどを処理するための要件により、メカニズム全体が少し複雑になります。これは、ドキュメントが79ページ(!)で重み付けされる理由の一部を説明している可能性があります。
メモリの使用法に関しては、スレッドごとの各変数には明らかに独自のスレッドごとのメモリが必要です(ただし、場合によっては、変数が最初にアクセスされたときにのみスペースが割り当てられるように、これを怠惰に行うことができます)。その後、いくつかの追加のデータ構造があります。オフセットテーブルなどに必要なものです。
パフォーマンス面では、TLS変数にアクセスするための追加コストは、主に変数のアドレスを取得することを中心に展開されます。x86 Linuxでは、GSレジスタはx86-64FSでスレッドIDを取得するための開始点として使用されます。通常、いくつかのポインター逆参照と、動的にロードされたコードの関数呼び出し(__tls_get_addr)があります。実装がスペースを割り当て、場合によってはすべてのTLS変数を初期化する必要があるため(遅延して行われない場合)、新しいスレッドの作成が遅くなるというコストもあります。
TLSは、古いスレッドセーフでないコードパターンを簡単にスレッドセーフにするのに適していますが(errnoを考えてください)、マルチスレッドの世界向けに最初から設計された新しいコードの場合、TLSが必要になることはめったにありません。