Using Thread Local Storage Program Example
Thread local storage (TLS) enables multiple threads of the same process to use an index allocated by the TlsAlloc() function to store and retrieve a value that is local to the thread. In this example, an index is allocated when the process starts. When each thread starts, it allocates a block of dynamic memory and stores a pointer to this memory in the TLS slot using the TlsSetValue() function. The CommonFunc() function uses the TlsGetValue() function to access the data associated with the index that is local to the calling thread. Before each thread terminates, it releases its dynamic memory. Before the process terminates, it calls TlsFree() to release the index.
Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.
Then, add the source file and give it a suitable name.
Next, add the following source code.
#include <windows.h>
#include <stdio.h>
#define THREADCOUNT 5
// Global variable
DWORD dwTlsIndex;
// Prototype
void ErrorExit(LPWSTR);
void CommonFunc(void)
{
LPVOID lpvData;
// Retrieve a data pointer for the current thread's TLS
lpvData = TlsGetValue(dwTlsIndex);
if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS))
ErrorExit(LTlsGetValue() error);
else
wprintf(LTlsGetValue() is OK!\n);
// Use the data stored for the current thread
wprintf(Lcommon: Current thread Id is %d: Its data pointer, lpvData = %lx\n, GetCurrentThreadId(), lpvData);
Sleep(5000);
}
DWORD WINAPI ThreadFunc(void)
{
LPVOID lpvData;
// Initialize the TLS index for this thread
// Allocates the specified number of bytes from the heap
lpvData = (LPVOID)LocalAlloc(LPTR, 256);
if(lpvData == NULL)
wprintf(LLocalAlloc() failed, error %d\n, GetLastError());
else
wprintf(LHeap memory has been successfully allocated!\n);
if (!TlsSetValue(dwTlsIndex, lpvData))
ErrorExit(LTlsSetValue() error);
else
wprintf(LTlsSetValue() is OK lol!\n);
wprintf(L\nThread Id %d: lpvData = %lx\n, GetCurrentThreadId(), lpvData);
CommonFunc();
// Release the dynamic memory before the thread returns
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData != 0)
LocalFree((HLOCAL)lpvData);
else
wprintf(LlpvData already freed!\n);
return 0;
}
int wmain(int argc, WCHAR **argv)
{
DWORD IDThread;
HANDLE hThread[THREADCOUNT];
int i;
DWORD Ret;
// Allocate a TLS index
if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
ErrorExit(LTlsAlloc() failed);
else
wprintf(LTlsAlloc() is OK!\n);
// Create multiple threads
for (i = 0; i < THREADCOUNT; i++)
{
hThread[i] = CreateThread(NULL, // default security attributes
0, // use default stack size
(LPTHREAD_START_ROUTINE) ThreadFunc, // thread function
NULL, // no thread function argument
0, // use default creation flags
&IDThread); // returns thread identifier
// Check the return value for success.
if (hThread[i] == NULL)
ErrorExit(LCreateThread() error\n);
else
wprintf(LCreateThread() #%u is OK. Thread ID is %u\n, i, IDThread);
}
for (i = 0; i < THREADCOUNT; i++)
{
Ret = WaitForSingleObject(hThread[i], INFINITE);
wprintf(LThe WaitForSingleObject() return value is 0X%.8x\n, Ret);
}
if(TlsFree(dwTlsIndex) != 0)
wprintf(LThe TLS index, dwTlsIndex was released!\n);
else
wprintf(LFailed to released TLS index, dwTlsIndex, error %d\n, GetLastError());
return 0;
}
void ErrorExit(LPWSTR lpszMessage)
{
fwprintf_s(stderr, L%s\n, lpszMessage);
ExitProcess(0);
}
Build and run the project. The following screenshot is a sample output.