Is Windows local storage value initialization?

I found a contradiction in MSDN regarding initial values โ€‹โ€‹for local thread storage. This page says:

When threads are created, the system allocates an array of LPVOID values โ€‹โ€‹for TLS, which are initialized to NULL.

This makes me think that if I call TlsGetValue with a valid index from a thread that never called TlsSetValue for the same index, then I should get a null pointer.

This page , however, says:

The programmerโ€™s task is to ensure that the thread calls TlsSetValue before calling TlsGetValue.

This suggests that you cannot rely on the value returned from TlsGetValue unless you are sure that it is explicitly initialized using TlsSetValue.

However, the second page at the same time reinforces the initialized-zero behavior, also saying:

The data stored in the TLS slot may have a value of 0 because it still has an initial value or because the stream, called the TlsSetValue function, is 0.

So, I have two statements that the data is initialized to zero (or 0), and one says that I should initialize it explicitly before reading the value. Experimentally, the values โ€‹โ€‹really seem to be initialized null pointers automatically, but I donโ€™t know if I can just succeed, and whether it will always be so.

DLL, DLL_THREAD_ATTACH. :

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 . , , .

+5
3

, , , TLS, . , .

, TLS, TlsFree, , , , , - . , 0, , , .

:

  • A TlsAlloc 1. 1 , 0.
  • A TlsSetValue(1, someValue).
  • A TlsGetValue(1) someValue .
  • A TlsFree(1).
  • B TlsAlloc 1.
  • B TlsGetValue(1) someValue , , A.

, TlsSetValue TlsGetValue. TlsGetValue .

: " ", , , , , .a >

Adrian , , โ€‹โ€‹ , A TlsFree(1), , B TlsGetValue(1), . , A , TlsSetValue(1) TlsFree(1).

+10

, , MSDN TlsAlloc:

, TLS. .

TlsAlloc , , . , TlsAlloc , :

void TlsExperiment() {
  DWORD index1 = ::TlsAlloc();
  assert(index1 != TLS_OUT_OF_INDEXES);
  LPVOID value1 = ::TlsGetValue(index1);
  assert(value1 == 0);  // Nobody else has used this slot yet.
  value1 = reinterpret_cast<LPVOID>(0x1234ABCD);
  ::TlsSetValue(index1, value1);
  assert(value1 == ::TlsGetValue(index1));
  ::TlsFree(index1);

  DWORD index2 = ::TlsAlloc();
  // There nothing that requires TlsAlloc to give us back the recently freed slot,
  // but it just so happens that it does, which is convenient for our experiment.
  assert(index2 == index1); // If this assertion fails, the experiment is invalid.

  LPVOID value2 = ::TlsGetValue(index2);
  assert(value2 == 0);  // If the TlsAlloc documentation is right, value2 == 0.
                        // If it wrong, you'd expect value2 == 0x1234ABCD.
}

Windows 7 32- 64- , VS 2010.

, TlsAlloc 0. , TlsAlloc - , , "" ( ), , , 0.

: , TlsFree, TlsAlloc, 0. , , , , TlsSetValue . โ€‹โ€‹ , .

+2

I do not see a contradiction. The second page simply tells you that the system initializes all the TLS slots to 0, but outside of some rudimentary bounds estimates there is no way to find out if a particular TLS index contains reliable data (it 0may be a valid set of -the-user!) And what you need make sure that the index you requested is the index you need and contains reliable data.

+1
source

All Articles