スレッドローカルストレージの初期値に関するMSDNの矛盾が見つかりました。 :Windowsのスレッドローカルストレージは値を初期化しますか?
スレッドが作成されると、システムはNULLに初期化されるTLSのLPVOID値の配列を割り当てます。
これは、TlsGetValueを同じインデックスのTlsSetValueを一度も呼び出さなかったスレッドから有効なインデックスで呼び出すと、NULLポインタを取得する必要があると私に信じています。
This pageは、しかし、こう述べています。
それはスレッドがTlsGetValueを呼び出す前のTlsSetValueを呼び出していることを確実にするために...プログラマ次第です。
これは、明示的にTlsSetValueで初期化されていない限り、TlsGetValueから返された値に依存できないことを示しています。
しかし同時にsecond pageも言って初期化ツーヌル挙動を強化:
データがNULL(または0)に初期化されているという2つのステートメントと、値を読み取る前に明示的に初期化する必要があるということがあります。実験的には、値は自動的にヌルポインタに初期化されているように見えますが、私はちょうど幸運を得ているかどうか、これがいつも正しいかどうかを知る方法はありません。をそれがまだその初期値を有するか、またはスレッドのでためTLSスロットに格納されたデータが0の値を有することができ
私はDLL_THREAD_ATTACHに割り当てるだけのDLLを使用しないようにしています。
LPVOID pMyData = ::TlsGetValue(g_index);
if (pMyData == nullptr) {
pMyData = /* some allocation and initialization*/;
// bail out if allocation or initialization failed
::TlsSetValue(g_index, pMyData);
}
DoSomethingWith(pMyData);
これは信頼できる安全なパターンですか?または、私はそれを読む前に各スレッドのスロットを明示的に初期化する必要がありますか?
更新:ドキュメントには、TlsAlloc zeros out the slots for the allocated indexと記載されています。したがって、スロットが以前にプログラムの別の部分で使用されていたかどうかは関係ありません。
良い推論ですが、TlsAllocはスロットをゼロに再初期化するので、コンポーネントBはコンポーネントAによって残されたガベージ値ではなく0に戻ります。私はさらに詳細な答えを追加しました。 –
@Adrian現在のスレッドのスロットを再初期化します。他のスレッドはまだねじ込まれている、と私は信じている。 [更新:他のスレッドは実際にねじ込まれていません。彼らはTlsFree時にはゼロになります。] –
おかげさまで、ありがとうございました。私はTlsFreeで再初期化されているのを見て回ったが、まだ他のスレッドをチェックしていなかった。 –