Thread Local Storage
^ ^ ^
So what is it used for exactly? Yes yes, I know it's used so that "Any thread of the process can subsequently use this index to store and retrieve values that are local to the thread." But can't you do that with pretty much any variable, as long as you do all the the synchronizing stuff properly? :confused:
Each thread gets its own storage slot. This makes it useful to store a thread specific value. The classic example is SetLastError(), GetLastError().
Now, consider how you would implement that functionality without some sort of thread local storage. Another example is being able to return a pointer to something in a thread safe manner. See gethostbyname(), etc.
// On process intialization.
// Get an index to an available slot.
g_idxLastError = TlsAlloc();
void SetLastError(DWORD dwErr)
TlsSetValue(g_idxLastError, (LPVOID) dwErr);
return (DWORD) TlsGetValue(g_idxLastError);
>>Now, consider how you would implement that functionality without some sort of thread local storage
How about wrapping the thread in a class, and putting a member DWORD called lastError in it (with thread sync stuff and all)... Oh wait, is that the point of it - to eliminate the need for manual sync'ing?
>>Another example is being able to return a pointer to something in a thread safe manner.
I'm not sure what you mean by that. Could you give an example?
>> How about wrapping the thread in a class, and putting a member DWORD called lastError in it (with thread sync stuff and all)... Oh wait, is that the point of it - to eliminate the need for manual sync'ing? <<
But then, how do you access that class? You'd would have to pass around the class reference to every function that needed to access the lastError variable (which is nearly all of the Windows api functions).
Or to put it another way, where are you going to store the class reference. Have a look at the TimerProc() callback. How are you going to get the class reference from within that callback?
>> I'm not sure what you mean by that. Could you give an example? <<
Well, the gethostbyname() function returns a pointer to memory, but it doesn't require you to free it. It can't use a static variable as the function can be used by multiple threads and only one instance of a static variable exists per process. Therefore, it (maybe) returns a pointer to dynamic memory and stores the pointer to that dynamic memory in TLS so it can be cleaned up when the thread exits. Using TLS for this purpose is generally not good design but should be noted.
The easiest way to think of TLS is like a global variable, but every thread gets a unique copy. Therefore, we can use a thread specific variable like a global variable, but without losing multi-threading capability.
In summary, we can usually pass around a variable intead of using TLS. However:
- Passing around a variable can be cumbersome - think of the GetLastError() example.
- Due to third party interface design it is not always possible. For example, it is not possible to pass a variable to the TimerProc() callback.
Have a look at the xMsgBox code I posted recently. It uses TLS to pass data into a timer procedure and a hook callback, neither of which provide a method to pass data to, except for TLS or global variables.
Ahh, I'd assumed earlier it was supposed to be used to pass data between threads...
Ok, but wouldn't only 1 TLS slot ever get allocated? Once the function sets m_bTlsInitialized to TRUE, isn't that the same for every thread? So wouldn't there be problems with several threads overwriting each other's TLS data? And along the same lines, since the index is a global variable, wouldn't it be the same if you just used a global int (or pointer) without bothering about special TLS accessing functions?
So in short, what I'm saying is, any function needing to access the TLS slot needs the index... but if it has some way of getting the index, then it should be able to get an actual variable in the exact same way. What makes TLS so special then? :confused:
Using Thread Local Storage
That example may clear things up, but in short, one slot is used by multiple threads to store whatever they want.
Ooooo, so the same slot index holds separate values for each thread? Now I'm starting to see the usefulness... :D Thanks, that clears it up a lot (assuming I've finally gotten it straight)!