Windows TLS (thread local storage)

Source: Internet
Author: User

Windows TLS (thread local storage)

I. TLS description and classification

We know that in a process, all threads are sharing the same address space. So, if a variable is global or static, then all threads are accessing the same part, and if one thread modifies it, it affects all other threads. However, we may not want this, so it is more recommended to use a stack-based automatic variable or function parameter to access the data because the stack-based variable is always associated with a particular thread.

But if at some point (for example, a DLL that might be a specific design) we need to rely on global variables or static variables, is there a way to ensure that they can be accessed without affecting each other in multithreaded programs? The answer is yes. The operating system helps us provide this functionality--TLS thread local storage. The role of TLS is to be able to relate data to specific threads of execution.

There are two ways to implement TLS: Static TLS and dynamic TLS. We will describe these two types of TLS separately below.

Second, Static TLS

1. Using static TLS

The reason for static TLS is that it is very simple to use in code, and we just need to write something like this:

__declspec (thread) DWORD mytlsdata=0;

We create a separate DWORD data for each thread in this program.

The prefix for __declspec (thread) is a modifier that Microsoft adds to the Visual C + + compiler. It tells the compiler that the corresponding variable should be placed in the executable file or in its own section of the DLL file . The variable following the __declspec (thread) must be declared as a global variable or a static variable in the function (or outside the function). You cannot declare a local variable of type __declspec (thread), you want to, because the local variable is always associated with a particular thread, what do you mean by adding this declaration?

2. Static TLS principle

The use of static TLS is so simple, so when we write the above code, the operating system and the compiler is how to deal with it?

First, when the compiler compiles the program, it puts all the declared TLS variables into their own section, which is named. TLS. The linker then combines all the. TLS sections from all object modules to form a large complete. TLS section in the resulting executable file or DLL file.
Then, in order for a program that contains static TLS to run, the operating system must participate in its operation. When the TLS application is loaded into memory, the system looks for the. TLS section in the executable file and dynamically allocates a large enough block of memory to hold all the static TLS variables. Each time the code in the application references one of these variables, it is converted to a memory location contained in the allocated memory block. Therefore, the compiler must generate some helper code to reference the static TLS variable, which will make your application larger and slower to run. On the x86 CPU, 3 auxiliary machine instructions will be generated for each reference static TLS variable. If another thread is created in the process, then the system captures it and automatically allocates another block of memory to hold the static TLS variable for the new thread. The new thread only has access to its own static TLS variable, and cannot access TLS variables that belong to other threads.

These are the cases where executables that contain static TLS variables run. Let's look at the DLL situation:

A, implicitly linking DLLs that contain static TLS variables

If an application uses a static TLS variable and implicitly links a DLL that contains a static TLS variable, when the system loads the application, it first determines the size of the application's. TLS section and adds this value to the size of all. TLS sections in the DLL that the application links to. When you create a thread in your process, the system automatically allocates a large enough chunk of memory to hold all the application-declared and all implicitly linked DLLs that contain the TLS variables.

B. Explicitly link DLLs that contain static TLS variables

Consider what happens when our application calls LoadLibrary to explicitly link to a DLL that contains static TLS variables. The system must look at all the threads that already exist in the process and expand their TLS memory blocks to accommodate the new DLL's memory requirements. Also, if you call FreeLibrary to release a DLL that contains a static TLS variable, then the TLS memory block associated with each thread in the process should be compressed.
For the operating system, this management task is too heavy. Therefore, although the system allows a library containing static TLS variables to be explicitly loaded at run time, it contains no corresponding initialization for TLS data. If you try to access this data, you can cause access violations!

So, remember: If a DLL contains static TLS data, do not explicitly link to this DLL, or you may get an error!

Third, dynamic TLS

1. Using Dynamic TLS

Dynamic TLS is a bit more cumbersome in program implementations than static TLS, and needs to be implemented through a set of functions:

DWORD TlsAlloc ();//Returns the index of the available location for the TLS array

BOOL TlsSetValue (DWORD dwtlsindex, lpvoid lptlsvalue); Sets the calling thread's TLS array index dwtlsindex to a value lptlsvalue

LPVOID TlsGetValue (DWORD dwtlsindex); Returns the value at the Dwtlsindex index of the TLS array of the calling thread

BOOL TlsFree (DWORD dwtlsindex); Releases the TLS array location index Dwtlsindex for all threads, marking the location as unused.

With the above four functions, we can see that using dynamic TLS is actually very easy and convenient.

2. Dynamic TLS principle

Let's look at the internal data structures that Windows uses to manage TLS:


The bit flags for thread local storage show a set of flags that are being used by all running threads in the process. Each flag can be set to free or inuse, indicating whether the TLS slot (slot) is in use. Microsoft guarantees that at least the tls_minimum_available bit flags are available for use. In addition, tls_minimum_available is defined as 64 in WinNT.h. WINDOWS2000 expands this flag array to allow more than 1000 TLS slots.

Each thread has an array of its own independent TLS slots for storing TLS data.
In order to use dynamic TLS, we first call TlsAlloc () to command the system to scan the bit flags of the process, find an available location, and return the index, or return tls_out_of_indexes if it is not found. In fact, in addition to this, the TlsAlloc function automatically empties the value of the corresponding index of the TLS array for all threads. This avoids problems that may have been caused by previously inherited values.
We can then call the TlsSetValue function to save a specific value for the corresponding index bit, and you can call TlsGetValue () to return the value of the index bit. Note that these two functions do not perform any test and error checking, and we must ensure that the indexes are properly allocated through TlsAlloc.
TlsFree should be called when all threads do not need to preserve an index bit of the TLS array. This function tells the system to set the index position of the bit flag array of the process to the Free State. If the run succeeds, the function returns True. Note that an error is generated if an attempt is made to free an index bit that is not allocated.
The use of dynamic TLS is a bit more cumbersome than static TLS, but it is still very simple whether it is used in an executable file or in a DLL. And when used in the DLL, there is no problem due to DLL link, so if you want to use TLS in the DLL, and do not guarantee that the customer always use implicit link, then use the implementation of dynamic TLS.

http://blog.csdn.net/xiaoliangsky/article/details/43158713

Reference: http://www.cppblog.com/Tim/archive/2012/07/04/181018.html

Here is a test:

#pragma once#include <stdio.h> #include <windows.h> #include <process.h>namespace smtlthdlocs{ typedef DWORD (WINAPI *thread_porc_ptr) (LPVOID lpparameter); const int thread_num = 3;const int index_num = 2;dword G_tls Index[index_num];int G_counta = 0;int G_countb = 100;void error_print (const char *msg = NULL) {printf ("The Thread: [%d ] occur a error:%s\n ",:: GetCurrentThreadID (), msg);} void Free_local_memory () {lpvoid Pdataa =:: TlsGetValue (g_tlsindex[0]); if (pdataa! = NULL):: LocalFree (PDATAA); LPVOID Pdatab =:: TlsGetValue (g_tlsindex[1]); if (pdatab! = NULL):: LocalFree (Pdatab);} void SetA () {int *pintdata = (int*):: LocalAlloc (LPTR, n); if (pintdata! = NULL) {pintdata[0] = ++g_counta;pintdata[1] = ++g _counta;} if (!::tlssetvalue (G_tlsindex[0], (LPVOID) pintdata)) {error_print ("TlsSetValue error"); Free_local_memory (); return;} Char *pstr = (char*):: LocalAlloc (LPTR, +), if (pStr! = NULL) {for (int i=0; i<16; ++i) {pstr[i] = ' A ' +i;}} if (!::tlssetvalue (G_tlsindex[1], (LPVOID) pSTR) {error_print ("TlsSetValue error"); Free_local_memory (); return;}} void Geta () {int *pintdata = (int*):: TlsGetValue (g_tlsindex[0]); if (pintdata = = NULL) error_print ("TlsGetValue pintdata Error "), char *pstr = (char*):: TlsGetValue (g_tlsindex[1]), if (pStr = NULL) error_print (" TlsGetValue pStr error ");p rintf ("Thread [%d}:%d%d%s\n",:: GetCurrentThreadID (), pintdata[0], pintdata[1], pStr);} void Setb () {int *pintdata = (int*):: LocalAlloc (LPTR, n); if (pintdata! = NULL) {pintdata[0] = ++g_countb;pintdata[1] = ++g _COUNTB;} if (!::tlssetvalue (G_tlsindex[0], (LPVOID) pintdata)) {error_print ("TlsSetValue error"); Free_local_memory (); return;} Char *pstr = (char*):: LocalAlloc (LPTR, +), if (pStr! = NULL) {for (int i=0; i<16; ++i) {Pstr[i] = ' a ' +i;}} if (!::tlssetvalue (G_tlsindex[1], (LPVOID) pStr)) {error_print ("TlsSetValue error"); Free_local_memory (); return;}} void Getb () {int *pintdata = (int*):: TlsGetValue (g_tlsindex[0]); if (pintdata = = NULL) error_print ("TlsGetValue pintdata "Error"); char *pstr = (char*):: TlsGetValue (g_tlsindex[1]), if (pStr = = NULL) error_print ("TlsGetValue pStr error");p rintf ("Thread [%d}:%d%d%s\n ",:: GetCurrentThreadID (), pintdata[0], pintdata[1], pStr);} DWORD WINAPI Thread_proca (lpvoid lpparameter) {SetA (); Getb (); Free_local_memory (); return 0;} DWORD WINAPI THREAD_PROCB (lpvoid lpparameter) {Setb (); Getb (); Free_local_memory (); return 0;} void Init_procarray (Thread_porc_ptr proc_ptr[], int len) {for (int i=0; i<len; ++i) {if (i%2) proc_ptr[i] = Thread_proca; else proc_ptr[i] = THREAD_PROCB;}} void Alloc_tls_index () {for (int i=0; i<index_num; ++i) {G_tlsindex[i] =:: TlsAlloc (); if (g_tlsindex[i] = = Tls_out_of_ INDEXES) {error_print ("tls_out_of_indexes");}}} void Free_tls_index () {for (int i=0; i<index_num; ++i) {if (0 = =:: TlsFree (G_tlsindex[i])) {error_print ("TlsFree error" );}}} void Test_tls_funa () {thread_porc_ptr Procarray[thread_num];init_procarray (Procarray, thread_num); HANDLE Threadhandler[thread_num];D word threadid[thread_num];alloc_tls_index (); for (int i=0; i<THREAD_NUM; ++i) {Threadhandler[i] =:: CreateThread (NULL,//default security Attributes0,//U) Se default stack size procarray[i],//thread function Namenull,//argument to thread Functi          On 0,//Use default creation Flags &threadid[i]); Returns the thread identifier}for (int i=0; i<thread_num; ++i) {:: WaitForSingleObject (Threadhandler[i], INFINITE);} Free_tls_index ();}}


Windows TLS (thread local storage)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.