Reading the following page in MSDN:
Using Thread Local Storage in a Dynamic-Link Library
I can't understand who is responsible for freeing the memory pointed by the TLS slot of each thread in the case of a
Per the documentation you linked to:
When a thread terminates, the entry-point function is called with the DLL_THREAD_DETACH value and the memory for that thread is freed.
That is the ideal time when the memory pointed to by the TLS slot should be freed, if the thread did not already do so before terminating. This is demonstrated in the example code provided:
case DLL_THREAD_DETACH: // Release the allocated memory for this thread. lpvData = TlsGetValue(dwTlsIndex); if (lpvData != NULL) LocalFree((HLOCAL) lpvData); break; case DLL_PROCESS_DETACH: // Release the allocated memory for this thread. lpvData = TlsGetValue(dwTlsIndex); if (lpvData != NULL) LocalFree((HLOCAL) lpvData); // Release the TLS index. TlsFree(dwTlsIndex); break;
However, per the DllMain entry point documentation:
When a DLL is unloaded from a process as a result of an unsuccessful load of the DLL, termination of the process, or a call to
FreeLibrary, the system does not call the DLL's entry-point function with the
DLL_THREAD_DETACHvalue for the individual threads of the process. The DLL is only sent a
DLL_PROCESS_DETACHnotification. DLLs can take this opportunity to clean up all resources for all threads known to the DLL.
So, you would have to keep track of the pointers you store in per-thread TLS slots in such a way that any pointers not already freed by the
DLL_THREAD_DETACH handler can be later freed by the
DLL_PROCESS_DETACH handler. For instance, by storing the pointers in a global thread-safe list.
Update: an alternative solution would be to have the
DLL_PROCESS_DETACH handler enumerate running threads, accessing the TIB/TEB (Thread Information/Environment Block) struct for each thread.
NtQueryInformationThread() can be used to retrieve a pointer to a thread's TIB/TEB. Amongst other things, the TIB/TEB also contains a pointer to the thread's TLS array.
Update: On Vista+, an alternative solution is to use FLS (fiber local storage) instead of TLS (thread local storage). The
FlsAlloc() function takes an optional callback. The
FlsCallback documentation states:
An application-defined function. If the FLS slot is in use, FlsCallback is called on fiber deletion, thread exit, and when an FLS index is freed.
FlsFree() documentation states:
Freeing an FLS index frees the index for all instances of FLS in the current process. Freeing an FLS index also causes the associated callback routine to be called for each fiber, if the corresponding FLS slot contains a non-NULL value.
Per the Fibers documentation:
A fiber can use fiber local storage (FLS) to create a unique copy of a variable for each fiber. If no fiber switching occurs, FLS acts exactly the same as thread local storage. The FLS functions (
FlsSetValue) manipulate the FLS associated with the current thread. If the thread is executing a fiber and the fiber is switched, the FLS is also switched.