Make a little progress every day-local thread storage in Linux (1)

Source: Internet
Author: User

Reprint please explain the source: http://blog.csdn.net/cywosp/article/details/26469435

When C/C ++ is used in Linux for multi-threaded programming, the most common problem we encounter is the multi-threaded read/write problem of the same variable. In most cases, this type of problem is handled by locking the machine, however, this has a great impact on the program performance. Of course, for data types that the system native supports atomic operations, we can use atomic operations for processing, this will improve the performance of the program. So how can we ensure thread security for custom data types that do not support atomic operations without locking? This article will explain how to solve this thread security problem in terms of local thread storage.
I. Data TypesIn C/C ++ programs, global variables, static variables defined in functions, and local variables often exist. For local variables, thread security issues do not exist, therefore, it is not within the scope of this article. Global variables and static variables defined in functions are shared variables that can be accessed by various threads in the same process. Therefore, they have multi-thread read/write problems. The content in the variable is modified in a thread, and other threads can perceive and read the changed content. This is very fast for data exchange, but due to the existence of multithreading, for the same variable, two or more threads may modify the memory content of the variable at the same time. At the same time, multiple threads can read the memory value when the variable is modified, if the corresponding synchronization mechanism is not used to protect the memory, the read data will be unpredictable and may even cause program crash. If you need to implement a new mechanism to implement variables that can be accessed by function calls within a thread but cannot be accessed by other threads, we call it Static memory local to a thread (local Static variable of the Thread), also known as TSD (thread-Specific Data), or local Thread storage (TLS: thread-Local Storage ). Each thread in the Program maintains a copy of the variable, which has been in this thread for a long time, operations on such variables do not affect other threads. For example:

Ii. One-time InitializationBefore explaining thread-specific data, let's take a look at one-time initialization. Multi-threaded programs sometimes have the following requirement: no matter how many threads are created, some data initialization can only happen once. For example, in a C ++ program, a class can only have one instance object in the lifecycle of the entire process. In the case of multiple threads, in order to ensure secure initialization of this object, the one-time initialization mechanism is particularly important. -- In the design mode, this implementation is often called Singleton ). Linux provides the following functions for one-time initialization:
# Include <pthread. h>
// Returns 0 on success, or a positive error number on errorInt pthread_once (pthread_once_t * Once_control, Void (* Init) (Void); With the once_control parameter, the function pthread_once () ensures that the function is called no matter how many threads, the caller-Defined Function directed by init is executed only once. The function to which init points does not have any parameters, in the form of void init (void ){ // Some variables initializtion in here}
In addition, the once_control parameter must be a pointer to the pthread_once_t type variable and point to the static variable initialized as PTHRAD_ONCE_INIT. A function like std: call_once () is provided after C ++ 0x. Its usage is similar to that of this function. For more information, see https://github.com/apusapp/swift/blob/master/swift/base/singleton.hpp.
Iii. Thread Local data APIThe following functions are provided in Linux to operate on local data of a thread:
# Include <pthread. h>
// Returns 0 on success, or a positive error number on errorInt pthread_key_create (pthread_key_t * Key, Void (* Destructor) (Void *));
// Returns 0 on success, or a positive error number on errorInt pthread_key_delete (pthread_key_t Key);
// Returns 0 on success, or a positive error number on errorInt pthread_setspecific (pthread_key_t Key, Const void * Value);
// Returns pointer, or NULL if no thread-specific data is associated with keyVoid * pthread_getspecific (pthread_key_t Key);

The pthread_key_create () function creates a new key for the local data of the thread and points it to the newly created key buffer. Because all threads can use the new keys returned, the parameter key can be a global variable (global variables are generally not used in C ++ multi-threaded programming, instead, separate classes are used to encapsulate local data in the thread. Each variable uses an independent pthread_key_t ). Destructor points to a custom function in the following format:
Void Dest (void * Value){ // Release storage pointed to by 'value'}
As long as the value associated with the key is not NULL when the thread ends, the function referred to by the destructor will be automatically called. If a thread has multiple threads storing local variables, the call sequence of the destructor function corresponding to each variable is uncertain. Therefore, the destructor function of each variable should be designed independently of each other.
The function pthread_key_delete () does not check whether a thread is using the local data variable of the thread or call the clear function destructor. Instead, it only releases the function for the next call of pthread_key_create. In a Linux thread, it also sets the related thread data item to NULL.
Because the system has a limit on the number of pthread_key_t types in each process, an infinite number of pthread_key_t variables cannot be created in the process. In Linux, you can use PTHREAD_KEY_MAX (defined in limits. h file) or the system calls sysconf (_ SC _THREAD_KEYS_MAX) to determine the maximum number of keys supported by the current system. In Linux, 1024 keys are used by default, which is sufficient for most programs. If a thread contains multiple local storage variables, You can encapsulate these variables into a data structure and associate the encapsulated data structure with a local variable of the thread, this reduces the use of key values.

The pthread_setspecific () function is used to store a copy of value in a data structure and associate it with the call thread and key. The parameter value usually points to a piece of memory allocated by the caller. When the thread ends, the pointer is passed as a parameter to the destructor function associated with the key. When a thread is created, local storage variables of all threads are initialized to NULL. Therefore, pthread_getspecific () must be called before using such variables for the first time () function to check whether the corresponding key is associated. If not, pthread_getspecific () allocates a memory and saves the pointer to the memory block through the pthread_setspecific () function.
The value of the parameter value can also be a variable value that can be forcibly converted to void * instead of pointing to the memory area allocated by the caller. In this case, the previous pthread_key_create () the function should set parameters Destructor is set to NULL.
The pthread_getspecific () function is the opposite of pthread_setspecific (), which extracts the value set by pthread_setspecific. Before using the retrieved value, it is best to convert void * To a pointer of the original data type.
4. deep understanding of the local thread storage mechanism1. a deep understanding of the implementation of local thread storage helps you use its APIs. A typical implementation includes the following Arrays:
  • A global (process-level) array used to store key-value information stored locally by the thread
The pthread_key_t type value returned by pthread_key_create () is only an index of the global array. The global array is marked as pthread_keys. Its format is roughly as follows:
Each element of the array is a structure containing two fields. The first field indicates whether the array element is in use, the second field is used to store a copy of The deconstruct function for this key and local thread storage change, that is, the destructor function.
  • Each thread also contains an array of pointers that are specific to the data blocks allocated to each thread (the pointer stored by calling the pthread_setspecific () function, that is, the value in the parameter)
2. Most Common implementations that store the value of the pthread_setspecific () function parameter are similar. In the figure, assume that pthread_keys [1] is allocated to the func1 () function, and the pthread API maintains a pointer array pointing to the local data block of the thread for each function, each array element corresponds to the global pthread_keys in the implementation of the local data key of the graph thread.

V. SummaryThe use of global or static variables is a common cause of non-thread security in multi-threaded programming. In multi-threaded programs, one of the common measures to ensure non-thread security is to use mutex locks for protection. This method reduces the concurrency performance and only one thread can read and write data. If the program can avoid using global variables or static variables, these programs are thread-safe and performance can be greatly improved. If some data can only be accessed by one thread, this type of data can be processed using the Thread Local Storage Mechanism. Although this mechanism will affect the execution efficiency of the program, however, for the use of the lock mechanism, these performance effects can be ignored. For a simple implementation of Linux C ++ Thread Local Storage, refer. The more high-performance local thread storage mechanism is to use _ thread, which will be discussed in the next section.



Refer:[1] Linux/UNIX System Programming Manual (I) [2] http://www.groad.net/bbs/thread-2182-1-1.html%3] http://baike.baidu.com/view/598128.htm



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.