Introduction to C++ thread_local
In C++, thread_local is defined as a specifier to define the thread-local data and this data is created when the thread is created and destroyed when the thread is also destroyed, hence this thread-local data is known as thread-local storage. This thread_local is one of the storage classes other than extern and static specifiers. Therefore a variable declared as thread_local. It copies its thread as each thread created the variable is also created and hence this thread_local specifier can be declared or defined only on variable and this cannot be applied to functions definition or declarations and the declaration can be done only during the static duration.
Working of thread_local in C++
In this article, we will discuss thread_local in C++. The thread_local data is a data which is also known as thread-specific data as this thread_local is a storage class specifier which by declaring any variable with thread_local specifier then this variable can store its data in thread-local storage which is allocated as each thread basis, which means that each variable is created when the thread is created and these variables will also be destroyed when the threads are destroyed. So the allocation of this thread-local storage by compilers can be allocated whenever necessary during loop-parallelization optimization performances.
In C++, the variables are declared as thread-local data using underscore (_) followed by thread keyword such as __thread int a, __thread char s, etc these variables can be accessed as any variable like global or file-scoped or function-scoped and as automatic variables are always thread-local has no effect and hence this thread-local specifier can be combined with static or extern specifiers. The initialization of such variables requires a static constructor and if this thread_local variable with namespace or class scope can be initialized as a part of thread startup and it is static only when a member of the class can only be thread-local and hence each variable can have one copy per thread. Whereas such initialized thread-local variables are allocated in .tdata sections and uninitialized ones are stored as variables defined with a “COMMON” symbol and for each new thread created or initialized the thread allocated a new block in thread-local storage with each thread having a thread pointer that points to the control block of thread and has the value of pointer of thread pointer of the present executing thread. So the thread-local storage can be created only when any new thread is created or when a thread refers to any thread-local storage block for the very first time after shared objects are loaded or at the program startup itself.
Now let us see an example of declaring variables as thread_local where it will have its own threads copy and we can refer it by its name then the current thread is used when this copy of each thread is associated. So let us see in the below example the variables can be declared thread_local for integer and string data type.
Example of C++ thread_local
Below is the example:
Code:
#include <iostream>
#include <string>
#include <mutex>
#include <thread>
std::mutexcoutMutex;
thread_localint n=2;
thread_localstd::string str("hello Educba from thread number and address of the string is");
void thread_integer(intn_val){
n=n_val;
}
void thread_cnt(){
std::cout<<n;
}
void thread_func(int td){
thread_integer(td);
++n;
thread_cnt();
}
void thread_string(std::string const& a2){
str+=a2;
std::lock_guard<std::mutex> guard(coutMutex);
std::cout<<str<<std::endl;
std::cout<< "&str: " <<&str<<std::endl;
std::cout<<std::endl;
}
intmain(){
n=4;
std::thread it1(thread_func,1);
std::thread it2(thread_func,2);
std::thread it3(thread_func,3);
it1.join();
it2.join();
it3.join();
std::cout<<n<<std::endl;
std::cout<<std::endl;
std::thread tt1(thread_string,"thread number 1");
std::thread tt2(thread_string,"thread number 2");
std::thread tt3(thread_string,"thread number 3");
std::thread tt4(thread_string,"thread number 4");
tt1.join();
tt2.join();
tt3.join();
tt4.join();
}
Output:
In the above program, we can see we have to include libraries like a thread for using thread_local specifier, iostream for having input-output values, string library for using or declaring string variables, and mutex library it is used for protecting shared data that can be accessed by multiple threads. Then we have declared two variables one of integer type named as “n” and another of string type “str” and both these variables we are declaring as thread_local to see the output. In this declaration, we have already given the initial values for both types for integer we are starting from the thread “2” and for string type we are printing the message written in the str value. Then we will be writing functions for reading the integer values until specified in the main function. Therefore as seen in the above screenshot when we are printing the threads of integer type starting from the thread number 2 to thread number 4 and we are displaying only 3 threads so in the output we can see first thread 2 is executed then thread 4, thread 3 and again it will execute thread 4. So it may vary while running this program. This idea can be cleared using the string type. So when we are executing the above program we can see first thread number 3 is executed, then thread 1, then thread 2 and last thread 4 are executed and the string declared in the string variable is displayed to the respective threads along with thread number. Hence we can see here each thread has its own copy. So in the above program, we can say we can match this with random number generator, here each thread has its own random number of the thread in sequence irrespective of other threads.
Conclusion
In this article, we can conclude that the thread_local in C++ is a specifier which are used for the variables to declare with thread_local as a keyword before the variables of any data type like int, string, char, etc. In this article, we have seen how the thread_local variable is allocated in its own memory called as thread-local storage and this thread_local variable has its own copy per thread. In this article, we have seen one simple example of creating threads by declaring the int type and string type variables as thread_local which requires thread library and mutex library for displaying the threads that are executing and has its own copy irrespective of other threads.
Recommended Articles
This is a guide to C++ thread_local. Here we also discuss the definition and working of c++ thread_local along with different examples and its code implementation. You may also have a look at the following articles to learn more –
4 Online Courses | 5 Hands-on Projects | 37+ Hours | Verifiable Certificate of Completion
4.5
View Course
Related Courses