CodeNebula
C++11coreintermediate

thread_local Storage (C++11 Addition)

C++11 · Modern Revolution · Compiler flag: -std=c++11

Explanation

The `thread_local` storage specifier declares variables with thread-local storage duration, meaning each thread gets its own independent copy of the variable.

Real-World Scenario

Maintain per-thread error codes or per-thread caches in a multi-threaded server without synchronization overhead.

Quick Snippet

snippet.cpp
thread_local int errorCode = 0;

void processRequest() {
    errorCode = doWork(); // each thread has its own errorCode
}

Full Example

thread_local.cpp
// CodeNebula - C++11 Example: Thread Local Storage
// Compile: g++ -std=c++11 -Wall -Wextra -pthread -o example thread_local.cpp
//
// This example demonstrates:
// - thread_local storage duration for variables
// - Each thread gets its own independent copy
// - thread_local with static, function-local, and class-static variables
// - Practical use cases: per-thread counters, caches, error codes

#include <iostream>
#include <thread>
#include <mutex>
#include <string>
#include <vector>

std::mutex coutMutex;

// ============================================================
// 1. Global thread_local variable
// ============================================================
thread_local int threadCounter = 0;
thread_local std::string threadName = "unnamed";

// ============================================================
// 2. Function with thread_local static
// ============================================================
int getCallCount() {
    thread_local int callCount = 0;  // Each thread starts at 0
    return ++callCount;
}

// ============================================================
// 3. Class with thread_local static member
// ============================================================
class Logger {
public:
    static thread_local int logCount;

    static void log(const std::string& msg) {
        ++logCount;
        std::lock_guard<std::mutex> lock(coutMutex);
        std::cout << "  [" << msg << "] log #" << logCount << std::endl;
    }
};

thread_local int Logger::logCount = 0;

// ============================================================
// 4. Worker function demonstrating independence
// ============================================================
void workerFunction(const std::string& name, int iterations) {
    threadName = name;
    threadCounter = 0;

    for (int i = 0; i < iterations; ++i) {
        ++threadCounter;
        getCallCount();
        Logger::log(name);
    }

    std::lock_guard<std::mutex> lock(coutMutex);
    std::cout << "  " << threadName
              << ": counter=" << threadCounter
              << ", calls=" << getCallCount() - 1
              << ", logs=" << Logger::logCount << std::endl;
}

int main() {
    std::cout << "=== Thread Local Storage ===" << std::endl;

    // Main thread usage
    std::cout << "\n--- Main thread ---" << std::endl;
    threadName = "main";
    threadCounter = 100;
    std::cout << "  Main threadName: " << threadName << std::endl;
    std::cout << "  Main threadCounter: " << threadCounter << std::endl;

    // Spawn worker threads
    std::cout << "\n--- Worker threads ---" << std::endl;
    std::thread t1(workerFunction, "Alpha", 3);
    std::thread t2(workerFunction, "Beta", 2);

    t1.join();
    t2.join();

    // Main thread values are unchanged
    std::cout << "\n--- After threads finish ---" << std::endl;
    std::cout << "  Main threadName: " << threadName << std::endl;
    std::cout << "  Main threadCounter: " << threadCounter << std::endl;
    std::cout << "  Main Logger::logCount: " << Logger::logCount << std::endl;

    std::cout << "\nKey insight: each thread had independent copies" << std::endl;

    return 0;
}

// Expected output (thread interleaving may vary):
// === Thread Local Storage ===
//
// --- Main thread ---
//   Main threadName: main
//   Main threadCounter: 100
//
// --- Worker threads ---
//   [Alpha] log #1
//   [Alpha] log #2
//   [Alpha] log #3
//   Alpha: counter=3, calls=3, logs=3
//   [Beta] log #1
//   [Beta] log #2
//   Beta: counter=2, calls=2, logs=2
//
// --- After threads finish ---
//   Main threadName: main
//   Main threadCounter: 100
//   Main Logger::logCount: 0
//
// Key insight: each thread had independent copies
Run command
g++ -std=c++11 -Wall -Wextra -pthread -o example thread_local.cpp