Linux programming-use of C + + per-thread (thread-local) variables

Source: Internet
Author: User
Tags terminates

Global or static variables defined in a process are all visible to all threads, that is, each thread operates a storage area together. And sometimes we may have this requirement: for a global variable, the modification of each thread is valid only within this thread, and the threads do not interfere with each other. That is, each thread shares the name of the global variable, but the value of the variable is just as modified and read as if it were agenda on this line.
Thread-local storage and line Chengte have data to achieve these requirements. 1. Thread-Local Storage

Thread-local storage provides a persistent per-thread storage, with each thread having a copy of the variable. A variable in the thread-local store persists until the thread terminates, and the store is automatically freed. A typical example is the definition of errno (uClibc-0.9.32), where each thread has its own copy of errno, preventing a thread from being distracted by other threads when it acquires errno.
To define a thread local variable is simple, simply include the __thread specifier in the declaration of a global or static variable. For example:

static __thread int Buf[max_error_len];

A variable that is defined so that only the modification of this thread can be seen in a thread.
With regard to the Declaration and use of thread-local variables, the following points need to be noted:

1. If the keyword static or extern is used in the variable declaration, then the keyword __thread must be followed.
2. As with normal global or static variable declarations, a thread local variable can set an initial value when declared.
3. You can use the C language access operator (&) to get the address of a thread-local variable.

To modify the local variables of another thread in one thread:
__thread variables are not completely hidden between threads, each thread holds its own copy, so the address of this variable for each thread is different. But this address is visible throughout the process, so one thread obtains the address of another thread's local variable, and can modify this local variable of another thread.

There are additional restrictions on the use of __thread variables in C + +:

1. In C + +, if you want to initialize when defining a thread-local variable, the initialized value must be a constant expression.
2. __thread can only modify pod types, that is, without custom constructs, copies, assignments, types of destructors, no non-static protected or private members, no base class and virtual functions, so there are many limitations to defining class. However, you do not need to consider this restriction to modify the class pointer type instead. 2. Line Chengte have data

This is the way in which the C + + language implements each thread variable, and POSIX thread uses the getthreadspecific and setthreadspecific components to implement this feature, so the compilation needs to be-pthread, but it's cumbersome to use in this way , and the efficiency is very low. But I'll talk about it briefly.
The following steps are required to use the line Chengte data:

1. Create a key that distinguishes the different lines from the Chengte data. Calling a function pthread_key_create () creates a key and only needs to be created once in the first thread that calls the function.
2. In different threads, the pthread_setspecific () function is used to associate this key with the value of a variable in this thread (the caller thread), so that different threads can save different values using the same key.
3. The pthread_getspecific () function can be used in each thread to get the value of the key in this thread.

Description of three interface functions:

#include <pthread.h>

int pthread_key_create (pthread_key_t * key, Void (*destructor) (void *));

Used to create a key that successfully returns 0.
The function destructor points to a custom function, which is defined as follows. When a thread terminates, the function is automatically executed for some destructor actions, such as releasing resources from the storage space bound to the key. If you do not need to deconstruct, you can set destructor to null.
void dest (void *value)
{
/* Release storage Pointed "value" *
}
The parameter value is a pointer to the CHENGTE that has a data block associated with the key.
Note that if a thread has multiple lines Chengte a block of data, then the order of invocation of each destructor is indeterminate, so the design of each destructor is independent of each other.

int pthread_setspecific (pthread_key_t key, const void * value);

Used to set the association of a key with a pointer or a value within this thread. Successfully returned 0.

void *pthread_getspecific (pthread_key_t key);

is used to get the value associated with the key, which is pointed to by the pointer to the function's return value. If the key is not already associated in the thread, the function returns NULL.

int Pthread_key_delete (pthread_key_t key);

Use to unregister a key for the next call to Pthread_key_create ().
Linux supports up to 1024 keys, typically 128, so the key is usually sufficient, and if a function requires multiple lines Chengte values with data, they can be encapsulated as a struct and then associated with only one key.

Write an example:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> pthread_key_t

Key
 static void Key_destrutor (void * value) {printf ("dest called\n"); /* In this example, the value of the associated key is not malloc, so no release action is necessary.
*/return (void) 0;
 int Get_pspec_value_int () {int * pvalue;
 pvalue = (int *) pthread_getspecific (key);
return *pvalue;
  } void * Thread_handler (void * args) {int index = * (int *) args);
  
  int pspec;
  Pspec = 0;

        /* Set key to the value of the association * * PTHREAD_SETSPECIFIC (key, (void *) &pspec);
   while (1) {sleep (4);
   /* Get key associated with value * * * Pspec = Get_pspec_value_int ();
   printf ("Thread Index%d =%d\n", index, PSPEC); /* Modify value, which is used in this example to test that the value of different threads does not interfere with each other.
   * * Pspec + + index;
        Pthread_setspecific (Key, (void *) &pspec);
return (void *) 0;
        int main () {pthread_t pid1;
        pthread_t Pid2;
        int ret;
  
  int index1 = 1, index2 = 2;
  
  struct Thr1_st m_thr_v, *p_mthr_v;/* Create a key */Pthread_key_create (&key, key_destrutor); if (0!= (ret = pthread_create (&AMP;PID1, NULL, Thread_handler, (void *) &index1)) {perror ("Create thread
   Failed: ");
        return 1; } if (0!= (ret = pthread_create (&pid2, NULL, Thread_handler, (void *) &index2)) {perror ("Create th
   Read failed: ");
  return 1;
  /* Set the association of key with value * * memset (&m_thr_v, 0, sizeof (struct thr1_st));

        Pthread_setspecific (Key, (void *) &m_thr_v);
    
    while (1) {sleep (3);
    /* Get key associated with value * * * P_mthr_v = (struct Thr1_st *) pthread_getspecific (key);
    printf ("Main len =%d\n", P_mthr_v->len); /* Modify value, which is used in this example to test that the value of different threads does not interfere with each other.
    * * P_mthr_v->len + + 5;
        Pthread_setspecific (Key, (void *) p_mthr_v);
  /* Unregister a key/Pthread_key_delete (key);
  Pthread_join (PID1, 0);

        Pthread_join (PID2, 0);
return 0;
 }

The above example shows how to define line Chengte with data. Because the data in this example is only a value, there is no need to register the destructor, and if it is a malloc pointer, it needs to be freed in the destructor, otherwise a memory leak will occur. Executing this program will see that each thread's modification of the value associated with the key is mutually exclusive, that is, the line Chengte has data storage.

It is also noteworthy that pthread_key_create () can only be called once in the first thread that uses the key, and in this case it is obvious to call in the main function. And if we want to implement a library function that needs to be created and used in this library function, then it will cause multiple calls to Pthread_key_create ().
The pthread_once () function resolves this problem by declaring the following:

#include <pthread.h>
int pthread_once (pthread_once_t *once_control, Void (*init) (void));

The function can do that no matter how many times a thread has called the function, it will only execute the custom init function when it is first invoked.
The parameter once_control is a pointer to a static variable initialized to Pthread_once_init, for example:

pthread_once_t Once_var = Pthread_once_init;

This variable controls the execution of the Init callback function only the first time it is invoked, by changing its state.

Resources
[1] Sun Jian Michael kerrisk. Linux/unix system Programming Manual [M]. People's postal press, 2014.
[2] thread-local Storage http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm [OL]. Lawrence Crowl, 2008-06-11.

[3] C + + ISO drafts http://www.csci.csusb.edu/dick/c++std/cd2/expr.html

Related Article

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.