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
threadLocalVar
is 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
count
variable is declared as bothstatic
andthread_local
. - Each thread has its own static instance of
count
, which is initialized and updated independently. - Despite being static,
count
is not shared across threads due to thethread_local
specifier.
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
logger
object 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_local
keyword ensures that each thread has its own instance of a variable. - Variables with
thread_local
storage duration are initialized once per thread and destroyed when the thread exits. - It can be combined with
static
orconst
, but not withextern
. - Useful for thread-specific storage without needing external synchronization mechanisms.
- Available in C++11 and later versions.