Thread-specific data, also known as thread-private data, is a mechanism for storing and locating data related to a particular thread. The reason we call this data thread-specific or thread-private is because each thread accesses its own independent copy of the data without worrying about synchronization with access to other threads.
Thread-specific data may seem complicated, but we can actually interpret it as an index and pointer. The key structure stores the index, which is the pointer that is stored in the pthread structure, pointing to the private data in the thread, usually the pointer returned by the malloc function.
POSIX requires a POSIX-compliant system to maintain an array of structures called keys for each process (1), and each structure in this array is called a thread-specific data element. POSIX specifies that the system implements a key structure array that must contain not less than 128 thread-specific elements, and that each thread-specific data element contains at least two things: using flags and destructor pointers. The flags in the key structure indicate whether the array element is used, and all the flags are initialized to "not used."
When a thread calls Pthread_key_create to create a new thread-specific data element, the system searches for an array of key structures in its process, finds the first unused element, and returns the key of that element through Keyptr, which is the index we said earlier. The second parameter of the Pthread_key_create function, destructor, is a function pointer to a destructor that is used for some post-processing work after the thread ends, and the amount parameter of the destructor is a pointer to the thread-specific data.
In addition to the process-wide array of key structures in the hinterland, the system maintains a thread structure for each thread in the process, calling this thread-specific structure the pthread structure , which is part of a pointer array corresponding to the key array (2). Its 128 pointers and the 128 possible keys (indexes) in the process are correlated one by one. The memory that the pointer points to is the line thread has data.
Following a specific process, starting a process and creating several threads, one thread (such as thread 1), to request thread-private data, the system calls Pthread_key_creat () to find the first unused element in the key structure array shown in Figure 1, and put its key, That is to say, look at the index (0-127), return to the caller, assuming that the returned index is 1, after the thread through the pthrea_getspecific () call to get the pkey[1] value of this thread, return a null pointer ptr = NULL, This pointer is the first address of the thread data that we can use with index 1, but he is now empty, so with malloc allocating a fast memory based on the actual situation, using pthread_setspecific () calls to point a pointer to the specific data just allocated to the memory area. After the completion of the process, key structure and pthread structure 3 are shown,
There are several function calls involved in manipulating thread-specific data:
#include <pthread.h>//successfully returned 0, the failure returned an error number. int Pthread_key_create (pthread_key_t *keyp, Void (*destructor) (void *)); Returns the thread-specific data, or null if no value is associated with the keyword. void *pthread_getspecific (pthread_key_t key); Successful return 0, failure returns the error number. int pthread_setspecific (pthread_key_t key, const void *value); pthread_once_t Initflag = Pthread_once_init; Successful return 0, failure returns error code. int pthread_once (pthread_once_t *initflag, Void (*INITFN) (void)); Successful return 0, failure returns the error number. int Pthread_key_delete (pthread_key_t *key);
Typical usage of thread-specific data is as follows:
void destructor (void *) pthread_key_t key; pthread_once_t init_done = Pthread_once_init; void Thread_init (void) { err = pthread_key_create (&key, destructor);} int threadfunc (void *arg) { Pthread_ Once (&init_done, thread_init); if (ptr = pthread_getspecific (key) = = NULL) { ptr = malloc (len); Pthread_setspecific (key,ptr); ... } ... }
When Pthread_key_create is called, it produces a key value for thread-specific data (TSD) that is visible to all threads (for example, all threads in the thread will get a value of pkey[1], but the actual data pointed to by this key is different, although all pkey[1], But instead of pointing to the same piece of memory, they point to the actual data that belongs to them, so if thread 0 changes the data pointed to by pkey[1], it is not able to image to thread n;
After a thread calls Pthread_setspecific, the specific data for each of the threads is bound to thread_key_t, although there is only one pthread_key_t, but the specific data for each thread is a separate memory space. The destructor function is executed when the thread exits.
/** Example 1: set/Get thread-specific data set/get thread-specific data in two threads, see if data in two threads is the same (definitely not the same O (∩_∩) o~) **/pthread_key_t Key; typedefstructTsd {pthread_t tid; Char*str; } tsd_t; //used to destroy the actual data that each thread points tovoidDestructor_function (void*value) { Free(value); cout<<"destructor ..."<<Endl; } void*thread_routine (void*args) { //setting thread-specific datatsd_t *value = (tsd_t *)malloc(sizeof(tsd_t)); Value->tid =pthread_self (); Value->str = (Char*) args; Pthread_setspecific (key, value); printf ("%s setspecific, address:%p\n", (Char*) args, value); //get thread-specific dataValue = (tsd_t *) pthread_getspecific (key); printf ("tid:0x%x, str =%s\n", (unsignedint) Value->tid, value->str); Sleep (2); //get thread-specific data againValue = (tsd_t *) pthread_getspecific (key); printf ("tid:0x%x, str =%s\n", (unsignedint) Value->tid, value->str); Pthread_exit (NULL); } intMain () {//so that one key is available for each thread,//but the actual area that each key binds to needs to be specified by each thread itselfPthread_key_create (&key, destructor_function); pthread_t Tid1, Tid2; Pthread_create (&TID1, NULL, Thread_routine, (void*)"Thread1"); Pthread_create (&tid2, NULL, Thread_routine, (void*)"thread2"); Pthread_join (TID1, NULL); Pthread_join (Tid2, NULL); Pthread_key_delete (key); return 0; }
/** Example 2: Use Pthread_once to initialize key only once note: the initialization of the key is put into Init_routine **/pthread_key_t Key; pthread_once_t Once_control=Pthread_once_init; typedefstructTsd {pthread_t tid; Char*str; } tsd_t; //thread-specific data destruction functions,//used to destroy the actual data that each thread points tovoidDestructor_function (void*value) { Free(value); cout<<"destructor ..."<<Endl; } //initializes the function, putting the initialization of the key into the function,//The inti_routine function can be guaranteed to run only oncevoidInit_routine () {pthread_key_create (&key, destructor_function); cout<<"init ..."<<Endl; } void*thread_routine (void*args) {Pthread_once (&Once_control, Init_routine); //setting thread-specific datatsd_t *value = (tsd_t *)malloc(sizeof(tsd_t)); Value->tid =pthread_self (); Value->str = (Char*) args; Pthread_setspecific (key, value); printf ("%s setspecific, address:%p\n", (Char*) args, value); //get thread-specific dataValue = (tsd_t *) pthread_getspecific (key); printf ("tid:0x%x, str =%s\n", (unsignedint) Value->tid, value->str); Sleep (2); //get thread-specific data againValue = (tsd_t *) pthread_getspecific (key); printf ("tid:0x%x, str =%s\n", (unsignedint) Value->tid, value->str); Pthread_exit (NULL); } intMain () {pthread_t tid1, Tid2; Pthread_create (&TID1, NULL, Thread_routine, (void*)"Thread1"); Pthread_create (&tid2, NULL, Thread_routine, (void*)"thread2"); Pthread_join (TID1, NULL); Pthread_join (Tid2, NULL); Pthread_key_delete (key); return 0; }
43883033
Http://www.360doc.com/content/18/0617/11/56818466_763036051.shtml
Pthread Thread-specific data