Starting with this article is another topic: Thread local Storage (threads locally Storage), before you introduce this concept, talk about variables and multithreading related knowledge.
Variable model under multi-threading
In a single-threaded model, a variable is defined with two dimensions, that is, where it is defined, and its modified properties (static, Extern,auto,register, and so on). The Extern property indicates that a variable is declared, independent of the definition, and not discussed here, while the register optimizes the variables into registers without discussion. The modifier properties associated with the variable definition are only auto and static. These two dimensions give you the types of variables and their behavior. Evaluate the behavior of a variable by often being from visibility and
The life cycle is assessed in terms of "where to define" and "Modify attributes" for variables, to derive "variable type" and to list a complete table from "visibility" and "life cycle" as follows:
where to define |
Modifier Properties |
Variable Type |
Life cycle |
Visibility of |
Outside the function |
Auto |
Global variables |
The entire program |
Globally visible |
Outside the function |
Static |
Global static variables |
The entire program |
The same. c file is visible |
Within a function |
Auto |
Local variables |
function begins execution to the end of the period |
Visible within function |
Within a function |
Static |
Static local Variables |
The entire program |
Visible within function |
There is a question about static local variables, which can only be used within a function, why is its life cycle global? In fact, it is not the same as the local variable, the local variable is created when the function begins execution, at the end of the function execution, it disappears, does not exist. While a static local variable, when the function is not executed, it already exists, which is why it is the whole life cycle of the program . When the function execution is finished, it still exists, and the next time the function is executed, it is executed based on the result of the previous execution. So it behaves the same as a global variable, except that it can be accessed only within a function.
Under single-threaded programming, all of this is well coordinated. Because the entire process has only one execution unit, there is only one execution code (or function) that accesses the same variable at any given time.
In multithreaded mode, however, all of this has changed. Under multithreaded mode, multiple execution units occur at the same time, i.e. the same function runs in multiple execution units at the same time
It is not necessary to bring up multiple threads and almost all remember to protect data by applying locks.
The local variables (life cycle in the function) are not affected by multithreading, because each line stacks is independent, multiple threads execute the function concurrently, and the variable part of the access board is one copy of each thread, and does not produce data contention (race).
But it's not that much of a global variable, a global static variable, or a static local variable that has a life cycle as an entire program . Data contention occurs when multiple execution units are accessing the variable at the same time under multi-threading. In this case, it is necessary to use lock for data protection in order to guarantee the correctness of the program logic.
Locking, the intuitive response is to put part of the code back to the era of serial execution, if the locking is very frequent, the whole process can execute concurrently the code is not high, the use of multi-threaded acceleration ratio is not high, the most important is not based on the number of processors to dynamically scale.
In the multi-route programming, many times the data is divided, different data regions to different threading, you can avoid multi-threading in the competition to access data. One problem to consider, however, is if individual threads execute functions (usually different threads execute the same function, but they do not have access to the same data), can the intermediate output of these functions be thread independent ? If you can be completely independent, there is no need for mutual exclusion between multiple threads and optimal scalability.
There are two solutions to this problem, with the first thought being that the inputs and outputs of these functions are all passed with parameters. But it is very demanding for programming, and sometimes such designs are often not optimal. Many times the intermediate output of the function needs to be saved using global variables (of course we don't recommend global variables flying around, but static global variables are common in a module), which requires lock protection and inefficiency.
In this scenario, each thread wants to see the global variables themselves, it does not want to see others, do not want others to modify it, it does not want to modify others, the global variable is also a form, the ultimate goal is that it can have a separate copy .
In order to solve the problem of high-efficiency programming under multi-threading, we must modify the original variable model slightly, and support an additional attribute, that is, whether the variable is a multiple execution unit (thread) sharing or a separate copy.
where to define |
Modifier Properties |
multiple execution unit sharing or | exclusive
Variable Type |
Life cycle |
Visibility of |
Outside the function |
Auto |
Shares |
Global variables |
The entire program |
Globally visible |
Outside the function |
Auto |
Exclusive |
Global Thread variables |
The entire program |
Globally visible |
Outside the function |
Static |
Shares |
Global static variables |
The entire program |
The same. c file is visible |
Outside the function |
Static |
Exclusive |
Global static thread variables |
The entire program |
The same. c file is visible |
Within a function |
Auto |
Exclusive |
Local variables |
Only when the function begins execution to the end of the period |
Within a function |
Within a function |
Static |
Shares |
Static local Variables |
The entire program |
Visible within function |
Within a function |
Static |
Exclusive |
Static local thread variables |
The entire program |
Visible within function |
Note that the local variable is inherently exclusive to the thread function, so it does not share this property value, and the variables for the entire program life cycle share and enjoy these two property values.
What is TLS
Write here, the definition of TLS is self-evident. TLS is all called the thread local Storage, that is, threads are stored locally. In single-threaded mode, all variables in the entire program life cycle are only one, because it is just an execution unit, while in multithreaded mode, some variables need to support each thread's ability to enjoy one share. This per-thread-exclusive variable is placed in a dedicated storage area for each thread, so it is called thread local storage (thread locally Storage) or thread-private data (threaded specific).
Linux supports two ways of defining and using TLS variables, as shown in the following table:
How to define |
Support Hierarchy |
access Mode |
__thread keywords |
Language level |
Exactly the same as the global variable |
Pthread_key_create function |
Run-level Library |
Pthread_get_specific and pthread_set_specific to read and write thread variables |
The __thread keyword supported by the application language is the simplest, and only needs to add a __thread keyword when defining the variable, and subsequent access to the variable remains completely intact, so this is supported at the language level and is implicit. The _thread keyword is a gcc extension of the C language, not defined by the C language standard, and of course the visual stdio under Windows expands with another keyword.
__thread Example
Here's a simple example of how the __thread keyword is used, and the actual effect.
__threadintvar =0;//var is defined as thread variable, and each number line has one copyvoid* Worker (void* arg);intMain () {pthread_t pid1,pid2; Pthread_create (&pid1,null,worker, (void*)0); Pthread_create (&pid2,null,worker, (void*)1); Pthread_join (Pid1,null); Pthread_join (Pid2,null);return 0; }void* Worker (void* Arg) {intIDX = (int) Arg;intI for(i =0; I < -; ++i) {printf("thread:%d ++var =%d\n", IDX, ++var);//Each thread only accesses its own share}}
The thread variables created and used using the Pthread_key_create/pthread_get_specific/pthread_set_specific function are described later, and we will not discuss them for the time being.
Later in the article, we use the term thread variable to represent a variable that each thread has a single copy of, and a TLS statement is used to represent a generic representation of the properties stored in this class of variables.
Talk about thread-local storage in Linux (1)-What is TLS