スレッド ローカル ストレージの初期値に関して、MSDN で矛盾を見つけました。 このページには次のように書かれています。
スレッドが作成されると、システムは TLS に LPVOID 値の配列を割り当てます。これらは NULL に初期化されます。
これにより、同じインデックスに対して TlsSetValue を呼び出したことのないスレッドから有効なインデックスを使用して TlsGetValue を呼び出すと、null ポインターを取得する必要があると考えるようになります。
スレッドが TlsGetValue を呼び出す前に TlsSetValue を呼び出すことを確認するのは、プログラマの責任です。
これは、TlsSetValue で明示的に初期化されていることが確実でない限り、TlsGetValue から返された値に依存できないことを示唆しています。
しかし、2 番目のページでは、次のようにも言って、null への初期化の動作を同時に強化しています。
TLS スロットに格納されたデータは、まだ初期値を持っているか、スレッドが TlsSetValue 関数を 0 で呼び出したため、値が 0 になることがあります。
したがって、データが null (または 0) に初期化されるという 2 つのステートメントと、値を読み取る前に明示的に初期化する必要があるという 1 つのステートメントがあります。実験的には、値は自動的に null ポインターに初期化されるように見えますが、運が良かっただけなのか、常にそうなのかどうかを知る方法はありません。
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 が割り当てられた index のスロットをゼロにすることも記載されています。そのため、スロットが以前にプログラムの別の部分で使用されていたかどうかは関係ないようです。