C++ thread_local Keyword
The thread_local keyword in C++ is used to declare variables with thread storage duration. This means that each thread has its own, independent instance of the variable, ensuring that data is not shared between threads.
Variables declared with thread_local are useful in multithreaded programming, where threads need their own copies of variables to avoid race conditions or unexpected data sharing. This keyword was introduced in C++11.
Syntax
</>
Copy
thread_local data_type variable_name = initial_value;
- thread_local
- Specifies that the variable has thread storage duration, meaning each thread gets its own instance.
- data_type
- The type of the variable.
- variable_name
- The name of the variable.
- initial_value
- An optional value used to initialize the variable.
Examples
Example 1: Using thread_local with a Simple Variable
In this example, you will learn the behavior of a thread_local variable in a multithreaded environment.
</>
Copy
#include <iostream>
#include <thread>
using namespace std;
thread_local int threadLocalVar = 0;
void incrementAndPrint(const string& threadName) {
threadLocalVar++;
cout << threadName << ": threadLocalVar = " << threadLocalVar << endl;
}
int main() {
thread t1(incrementAndPrint, "Thread 1");
thread t2(incrementAndPrint, "Thread 2");
t1.join();
t2.join();
return 0;
}
Output:
Thread 1: threadLocalVar = 1
Thread 2: threadLocalVar = 1
Explanation:
- The variable
threadLocalVaris declared asthread_local, so each thread has its own copy. - Both threads increment their own instance of
threadLocalVar, resulting in separate values for each thread. - There is no interference or shared state between threads, ensuring thread safety.
Example 2: Using thread_local with a Function Static Variable
This example shows how thread_local affects static variables within a function.
</>
Copy
#include <iostream>
#include <thread>
using namespace std;
void updateStaticVar(const string& threadName) {
thread_local static int count = 0; // Each thread gets its own static variable
count++;
cout << threadName << ": count = " << count << endl;
}
int main() {
thread t1(updateStaticVar, "Thread 1");
thread t2(updateStaticVar, "Thread 2");
t1.join();
t2.join();
return 0;
}
Output:
Thread 1: count = 1
Thread 2: count = 1
Explanation:
- The
countvariable is declared as bothstaticandthread_local. - Each thread has its own static instance of
count, which is initialized and updated independently. - Despite being static,
countis not shared across threads due to thethread_localspecifier.
Example 3: Using thread_local with Complex Data Types
This example demonstrates a thread_local variable with a custom class type.
</>
Copy
#include <iostream>
#include <thread>
#include <string>
using namespace std;
class Logger {
string threadName;
public:
Logger(const string& name) : threadName(name) {}
void log(const string& message) {
cout << "[" << threadName << "] " << message << endl;
}
};
thread_local Logger logger("Default");
void threadFunction(const string& threadName) {
logger = Logger(threadName); // Initialize the logger for this thread
logger.log("Starting thread work.");
logger.log("Finishing thread work.");
}
int main() {
thread t1(threadFunction, "Thread 1");
thread t2(threadFunction, "Thread 2");
t1.join();
t2.join();
return 0;
}
Output:
[Thread 1] Starting thread work.
[Thread 1] Finishing thread work.
[Thread 2] Starting thread work.
[Thread 2] Finishing thread work.
Explanation:
- The
loggerobject is declared asthread_local, so each thread gets its own independent instance. - The object is initialized with a unique name for each thread, ensuring thread-specific behavior.
- Each thread executes its logging without interference from other threads.
Key Points to Remember about thread_local Keyword
- The
thread_localkeyword ensures that each thread has its own instance of a variable. - Variables with
thread_localstorage duration are initialized once per thread and destroyed when the thread exits. - It can be combined with
staticorconst, but not withextern. - Useful for thread-specific storage without needing external synchronization mechanisms.
- Available in C++11 and later versions.
