Friday, May 10, 2024

MultiThreading: Understanding Thread-Local Data in C++

In multi-threaded program, `thread_local` allows each thread to have its own separate instance of variable and changes made to it in one thread would not affects its value in another thread.


Program:

#include <iostream>

#include <thread>

#include <mutex>

 

using namespace std;

std::mutex mutexCout;

 

thread_local string welcomeMessage = "Executing ";

 

void checkThreadLocal(string const& threadName)

{

welcomeMessage.append(threadName);

           lock_guard<mutex> guard(mutexCout);

           cout << welcomeMessage << endl;

}

 

int main()

{

           thread t1(checkThreadLocal, "thread1 ");

           thread t2(checkThreadLocal, "thread2 ");

           thread t3(checkThreadLocal, "thread3 ");

           thread t4(checkThreadLocal, "thread4 ");

 

           t1.join();

           t2.join();

           t3.join();

           t4.join();

}


Output:

Executing thread1

Executing thread2

Executing thread3

Executing thread4


Output of program shows that local string is created for each string welcomeMessage


When to use thread_local ?
  1. Thread-specific data: Sometimes, you need data that is specific to each thread. For example, you might want to maintain a thread-local cache or store thread-specific configuration settings. thread_local allows you to declare variables that are unique to each thread, making it convenient to work with thread-specific data.
  2. Thread safety: In multi-threaded programs, global variables are shared among threads and can lead to race conditions if not properly synchronized. By using thread_local, you can avoid race conditions by ensuring that each thread has its own copy of the variable. This can simplify thread synchronization and improve thread safety.
  3. Performance optimization: In some cases, using thread-local variables can improve performance by reducing contention for shared resources. For example, if multiple threads frequently access a global variable, using thread_local to declare a separate copy of the variable for each thread can reduce cache invalidation and contention, leading to better performance.
  4. Avoiding mutex overhead: In scenarios where thread-local variables can replace the need for mutexes or other synchronization mechanisms, using thread_local can help avoid the overhead associated with locking and unlocking mutexes, leading to better performance.