Yangshazhou
October 2001
This is a column for POSIX thread programming. The author will tell you the POSIX thread library API on the basis of clarifying the concept. This article is the second article will tell you the private data of the thread.
One. Concepts and roles In single-threaded programs, we often use "global variables" to achieve multiple functions. In multi-threaded environments, due to data space is shared, global variables are also common for all threads. However, sometimes it is necessary to provide thread private global variables in an application design, but only in a thread, but can access multiple functions, such as programs that may require a linked list for each thread, and use the same function to operate, The easiest way is to use thread-related data structures related to different variable addresses. Such a data structure can be maintained by the POSIX thread library, called thread private data (Thread-Specific Data, or TSD).
two. Create and log out POSIX define two APIs to create and log out of TSD, respectively:
INT PTHREAD_KEY_CREATE (PTHREAD_KEY_T * Key, Void (* destr_function) (void *))
This function assigns an item from the TSD pool, assigns its value to Key for use. If DESTR_Function is not empty, the data associated with the key is called DESTR_Function () to release the assigned buffer when the thread exits (pThread_exit ()).
No matter which thread calls pthread_key_create (), the created key is all threads accessible, but each thread can fill in different values according to their own needs, which is equivalent to providing a global game with different values. variable. In the implementation of LinuxThreads, the TSD pool represents an array of structures:
Static struct pthread_key_struct pthread_keys [pthread_keys_max] = {{0, null}};
Creating a TSD is equivalent to setting one of the structural arrays to "in_use" and returns its index to * Key, and then set the Destructor function to be DESTR_Function.
Log out of a TSD to use the following API:
INT PTHREAD_KEY_DELETE (PTHREAD_KEY_T KEY)
This function does not check if there is a thread that is using the TSD, nor does it call the cleaning function (DESTR_FUNCTION), but only releases TSD to the next call pthread_Key_Create (). In LinuxThreads, it will also set the thread data item associated with it (see "Access").
three. The reading and writing of the TSD is made through a special POSIX THREAD function, and its API is defined as follows:
INT pthread_setspecific (pthread_key_t key, const void * pointer)
Void * pthread_getspecific (pthread_key_t key)
When writing (pthread_setspecific ()), the value of the Pointer (not the content referred to) is associated with Key, and the corresponding read function will read the data associated with the key. Both data types are set to void *, so you can point to any type of data.
In LinuxThreads, a two-dimensional VOID * pointer array located in the thread description structure (_pthread_descr_struct) is used to store data associated with Key, and 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)
Where PTHREAD_KEYS_MAX is defined in /usr/include/bits/local_lim.h, the one-dimensional array size is 32. The location of the specific storage is obtained by the Key value by the KEY value:
IDX1ST = key / pthread_key_2ndlevel_size
IDX2nd = key% pthread_key_2ndlevel_size
That is, data is stored in a sparse matrix of 32 × 32. Similarly, when the access is also calculated by the key value, the location index is obtained by similar calculations, and then removes the content returns.
four. Examples of Examples The following examples do not have any actual meaning, just explain how to use, and can use this mechanism to reach the purpose of storage thread private data.
#include
#include
Pthread_key_t key;
Void echomsg (int T)
{
Printf ("Destructor Excuted In Thread% D, PARAM =% D / N", PTHREAD_SELF (), T);
}
Void * child1 (void * arg)
{
INT TID = pthread_self ();
Printf ("Thread% D ENTER / N", TID);
Pthread_setspecific (key, (void *) TID);
Sleep (2);
Printf ("Thread% D returns% D / N", TID, PTHREAD_GETSPECICIC (KEY));
Sleep (5);
}
Void * child2 (void * arg)
{
INT TID = pthread_self ();
Printf ("Thread% D ENTER / N", TID);
Pthread_setspecific (key, (void *) TID);
Sleep (1);
Printf ("Thread% D returns% D / N", TID, PTHREAD_GETSPECICIC (KEY));
Sleep (5);
}
Int main (void)
{
Int Tid1, TID2;
Printf ("Hello / N");
Pthread_key_create (& Key, Echomsg);
Pthread_create (& TID1, NULL, Child1, NULL);
Pthread_create (& TID2, NULL, Child2, NULL);
Sleep (10);
Pthread_key_delete (key);
Printf ("Main Thread EXIT / N");
Return 0;
}
Give routine creation two threads Set the same thread private data for its own thread ID, in order to verify its privateness, the program is displayed for the write and read of the two threads, and can be seen from the program operation results. The two threads do not interfere with the modifications of TSD. At the same time, when the thread exits, the cleaning function will be executed automatically, the parameters are TID. About the author Yangshazhou, male, now attracting a Ph.D. in computer software in computer software.