When a function in a thread needs to create private data, the private data remains consistent between calls to the function, and the data can be statically allocated to the memory, when we adopt a naming range, we may be able to implement it in functions, files (static), or global (extern ). But it is not that simple when it comes to threads. In a single-threaded program, we often use global variables to share data among multiple functions. In a multi-threaded environment, global variables are shared by all threads because data space is shared. However, sometimes it is necessary to provide a global variable private to the thread in the application design, which is only valid in a thread, but can be accessed across multiple functions. For example, the program may require each thread to maintain a linked list, the simplest way to use the same function operation is to use the thread-related data structure with the same name and different variable addresses. Such a data structure can be maintained by the POSIX thread library.
Data, or TSD ).
Thread private data allows each thread to store a copy of the variable. Each thread has a string of thread private data indexed by a common "key" value. The keys are the same for each thread, however, each thread can associate its independent key value with the shared key. Each thread can change its private value for the key at any time, this does not affect keys or any foreign key values.
In the POSIX thread, the key value required here is to create a variable of the pthread_key_t type. And define the following API to create TSD:
int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)) ;
This function allocates an item from the TSD pool. Its first parameter key is a pointer to the key value, and the second parameter is a function pointer. if the pointer is not empty, when the thread exits, destr_function () is called with the data associated with the key as the parameter to release the allocated buffer.
No matter which thread calls pthread_key_create (), the created key is accessible to all threads, but each thread can enter different values in the key according to its own needs, this is equivalent to providing a global variable with the same name and different values. In linuxthreads implementation, the TSD pool is represented by a structure array:
static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = { { 0, NULL } };
Creating a TSD is equivalent to setting an item in the structure array to "in_use", returning its index to * key, and then setting the destructor function to destr_function.
Sell a TSD using the following API:
int pthread_key_delete(pthread_key_t key)
This function does not check whether a thread is using the TSD, nor call the cleanup function (destr_function). Instead, it only releases the TSD for the next call of pthread_key_create. This function does not check whether a thread is using the TSD, nor call the cleanup function (destr_function). Instead, it only releases the TSD for the next call of pthread_key_create.
All TSD reads and writes are performed through the special POSIX thread function. Its API definition is as follows:
int pthread_setspecific(pthread_key_t key, const void *pointer)void * pthread_getspecific(pthread_key_t key)
When writing (pthread_setspecific (), the pointer value (not the content referred to) is associated with the key, and the corresponding READ function reads the data associated with the key. The data type is set to void *, so it can point to any type of data.
In linuxthreads, a two-dimensional void * pointer array in the thread description structure (_ pthread_descr_struct) is used to store the data associated with the key. The array size is described by the following macros:
#define PTHREAD_KEY_2NDLEVEL_SIZE 32#define PTHREAD_KEY_1STLEVEL_SIZE \((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1)/ PTHREAD_KEY_2NDLEVEL_SIZE)
In/usr/include/bits/local_lim.h, pthread_keys_max is defined as 1024, so the size of one-dimensional array is 32. The specific storage location is calculated by the key value as follows:
idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZEidx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE
That is to say, data is stored in a 32 × 32 sparse matrix. Similarly, during access, the key value is calculated similarly to obtain the index of the data location, and then the content is retrieved and returned.
Next let's take a look at how to use this thread's private data (TSD). Let's take this one I wrote myself as an example,
# Include <stdio. h> # include <stdlib. h> # include <string. h> # include <pthread. h> # include <unistd. h> # include <sys/types. h> pthread_key_t key; // The initial definition thread private data key typedefstruct tsd_tag {// custom data type pthread_t thread_tg; char * string;} tsd_t; void destructor (tsd_t * value_pointer) {// printf ("thread % lu ends, Param = % s \ n", value_pointer-> thread_tg, value_pointer-> string); free (value_pointer ); value_pointer = NULL;} void * thread_routine (void * Arg) {// tsd_t * value_pointer = (tsd_t *) malloc (sizeof (tsd_t )); value_pointer-> string = (char *) ARG; value_pointer-> thread_tg = pthread_self (); printf ("thread % lu is running \ n", value_pointer-> thread_tg ); pthread_setspecpacific (Key, (void *) value_pointer); sleep (3); printf ("thread % lu returns % s \ n", value_pointer-> thread_tg, (tsd_t *) pthread_getspecific (key)-> string); sleep (4);} int main (INT argc, char * argv []) {pthread_t thid1, thid2; printf ("main thread begins running \ n"); pthread_key_create (& Key, (void *) destructor); pthread_create (& thid1, null, thread_routine, "thread 1 "); pthread_create (& thid2, null, thread_routine, "thread 2"); sleep (8); pthread_key_delete (key ); // Delete the private data key of the thread printf ("main thread exit \ n"); Return 0 ;}
This Code creates two threads respectively thread1 and thread2 at the beginning, but all of them call the same function thread_routine (), which is ensured by the key-value Association of the private data of the thread, the two threads privatize the data of the same data type tsd_t to achieve different data processing results.
The following is the running result of the program: