Pthread learning notes (4)-POSIX Thread Programming Guide for the trek journey (2)

Source: Internet
Author: User

Original article link

 

Concepts and functions

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. But sometimes
It is necessary to provide a global variable private to the thread in the application design. It is valid only in a thread, but can be accessed across multiple functions.
For example, the program may require each thread to maintain a linked list and use the same function operation.
The simplest way 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, which is called the thread private data.
(Thread-
Specpacific
Data, or TSD ).

 

Create and log out

POSIX defines two APIs for creating and canceling TSD:

 

This function allocates an item from the TSD pool and assigns the value to the key for future access.
. If destr_function is not empty, when the thread exits (pthread_exit (), destr_function () is called with the data associated with the key as the parameter to release the allocated buffer.
(Used for finishing work ).

 

Int pthread_key_create (pthread_key_t * Key, void (* destr_function) (void *));

 

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 as needed
This is equivalent to providing a global variable with the same name and different values. In the implementation of linuxthreads, the TSD pool uses a structured Array
Indicates:

Static struct pthread_key_struct pthread_keys [pthread_keys_max] ={{ 0, null }};

 

Creating a TSD is equivalent
Set an item in the structure array to "in_use"
And return its index to * key, and then set the destructor function to destr_function.

To log out of a TSD instance, use the following API:

Int pthread_key_delete (pthread_key_t key );

 

This function does not check whether a thread is using the TSD, nor does it call the cleanup function (destr_function)
Instead of releasing TSD for the next call.
Pthread_key_create ()
. In linuxthreads, it also sets the related thread data item to null.
(See "access") (whether setting null alone causes memory leakage
?).

 

Access

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); <br/> void * pthread_getspecific (pthread_key_t key); <br/>

 

When writing (pthread_setspecific (),
) (Is there a problem with this operation? The pointer passed in as a function parameter is only a copy of the original pointer, right? Write Program test!
Test results show that I am wrong ......) Associated with key
(Is the underlying implementation similar to the structure of the red/black tree?
), And the corresponding READ function reads the data associated with the key. All data types are set to void
*, So it can point to any type of data
.

Test code:

# Include <iostream> <br/> # include <cstdio> <br/> using namespace STD; <br/> void checkpointervalue (const void * pvoid) <br/>{< br/> printf ("the pointer's value is: % P/N", pvoid ); <br/>}< br/> int main () <br/>{< br/> int I = 100; <br/> int * pint = & I; <br/> printf ("original pointer's value = % P/N", pint); <br/> checkpointervalue (pint); <br/> return 0; <br/>}

The output result is equal.

 

In linuxthreads, a two-dimensional void in the thread description structure (_ pthread_descr_struct) is used.
* The pointer array stores the data associated with the key. The array size is described by the following macros:

# Define pthread_key_2ndlevel_size 32 <br/> # define finished/<br/> (pthread_keys_max + pthread_key_2ndlevel_size-1) <br/>/pthread_key_2ndlevel_size) <br/> // in/usr/include/bits/local_lim.h, pthread_keys_max is defined as 1024. <br/> // the size of the one-dimensional array is 32. The specific storage location is calculated by the key value: <br/> idx1st = key/pthread_key_2ndlevel_size; <br/> idx2nd = 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. (To put it simply, simulate a one-dimensional array as a two-dimensional array, obtain the layer that belongs to by division, and obtain the elements of the layer through the remainder operation.
In the preceding code, the formula for calculating the one-dimensional length is (1024 + 32-1)/32 = static_cast <int> (32.9) = 32.
)

 

Example

The following example shows how to use it and how to use this mechanism to store the private data of a thread.

 

# Include <stdio. h> <br/> # include <pthread. h> <br/> pthread_key_t key; <br/> void echomsg (INT t) <br/>{< br/> printf ("destructor excuted in thread % d, param = % d/N ", pthread_self (), T); <br/>}< br/> void * Child1 (void * Arg) <br/>{< br/> int tid = pthread_self (); <br/> printf ("thread % d enter/N", tid ); <br/> pthread_setspecific (Key, (void *) tid); <br/> sleep (2 ); <br/> printf ("thread % d returns % d/N", tid, pthread_getspecific (key); <br/> sleep (5 ); <br/>}< br/> void * child2 (void * Arg) <br/>{< br/> int tid = pthread_self (); <br/> printf ("thread % d enter/N", tid); <br/> pthread_setspecific (Key, (void *) tid ); <br/> sleep (1); <br/> printf ("thread % d returns % d/N", tid, pthread_getspecific (key )); <br/> sleep (5); <br/>}< br/> int main (void) <br/>{< br/> int tid1, tid2; <br/> printf ("Hello/N"); <br/> pthread_key_create (& Key, echomsg); <br/> pthread_create (& tid1, null, Child1, null); <br/> pthread_create (& tid2, null, child2, null); <br/> sleep (10); <br/> pthread_key_delete (key ); <br/> printf ("main thread exit/N"); <br/> return 0; <br/>}

 

Create two threads for the routine and set the private data of the same thread as their own thread ID respectively. to verify their private data, the program staggered the time for writing and reading private data of the two threads, the program running result shows that the two threads do not interfere with the modification of TSD. At the same time, when the thread exits, the cleanup function is automatically executed, and the parameter is tid.

 

The above program is not very running, mainly because of some parameter conversion problems, which may be the reason why I use g ++ for compilation.


In addition, the underlying types of pthread_t and pthread_key_t are as follows:

Typedef unsigned long int pthread_t;

Typedef unsigned int pthread_key_t;

 

The code I debug is as follows:

 

# Include <stdio. h> <br/> # include <pthread. h> <br/> # include <unistd. h> <br/> pthread_key_t key; <br/> // here t is used as int <br/> void echomsg (void * t) <br/>{< br/> printf ("destructor executed in thread % d, Param = % d/N", <br/> (INT) pthread_self (), (INT) T); <br/>}< br/> void * Child1 (void * argv) <br/>{< br/> int tid = pthread_self (); <br/> printf ("thread % d enter/N", tid); <br/> pthread_setspecific (Key, (void *) (T ID); <br/> sleep (2); <br/> printf ("thread % d returns % d/N", tid, (INT) pthread_getspecific (key); <br/> sleep (5); <br/>}< br/> void * child2 (void * argv) <br/>{< br/> pthread_t tid = pthread_self (); <br/> printf ("thread % d enter/N", (INT) tid ); <br/> pthread_setspecific (Key, (void *) (TID); <br/> sleep (1 ); <br/> printf ("thread % d returns % d/N", (INT) tid, (INT) pthread_getspecific (key); <br/> sleep (5 ); <br/>}< br/> int Main () <br/>{< br/> // The underlying layer of pthread_t is set to typedef unsigned int pthread_t <br/> pthread_t tid1, tid2; <br/> printf ("Hello! /N "); <br/> pthread_key_create (& Key, echomsg); <br/> pthread_create (& tid1, null, Child1, null ); <br/> pthread_create (& tid2, null, child2, null); <br/> sleep (10); <br/> pthread_key_delete (key ); <br/> printf ("main thread exit/N"); <br/> return 0; <br/>}< br/>


I would like to thank the author of the original article for its link at the beginning of this article. If you want to reprint it, add the original author information.

(The text marked red is what I personally think is important, and the blue is my own notes)

 

P.s. Long int in my 32-bit machine, the length is 4, consistent with the length of the INT (the length of long is 8)

 

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.