thread-local storage
/ TLS, said by its letters /
Sometimes you want a variable that is global in scope but private to each thread — for example, errno, where two threads making system calls at the same time must not clobber each other's error code. If errno were one shared global, the threads would race; if you passed it around by hand, every call signature would bloat. Thread-local storage is the mechanism that gives each thread its OWN separate copy of a designated variable, automatically, while you write code that just names the variable normally.
In C you mark such a variable with the keyword _Thread_local (C11) or the older compiler keyword __thread, for example '_Thread_local int errno_value;'. The implementation reserves a small block of per-thread memory, called the thread-control block area, and every thread gets its own block. Each thread-local variable is assigned a fixed OFFSET within that block, and a special CPU register (on x86-64, the fs register points at the thread block) lets code find the current thread's block in one step. So reading a thread-local variable becomes 'take the per-thread base from the fs register, add this variable's fixed offset, read'. The dynamic linker and the C runtime cooperate to set up each thread's block, including initializing variables that have non-zero initial values, and to lay out the offsets so that the main executable and each shared library get non-overlapping space (there are several TLS access models — local-exec, initial-exec, and the more general dynamic ones used by dlopen'd libraries — that trade speed for flexibility).
It matters because TLS is how thread-safe libraries keep per-thread state without locks or explicit passing: errno, locale buffers, allocator caches, and random-number state all commonly live in TLS. The honest caveats: a thread-local variable is not shared, so you cannot use it to communicate between threads; its address is only valid within the thread that owns it, so passing &x of a thread-local to another thread is a bug; and the very first access to TLS in a dynamically loaded library can be slightly slower because it may need an extra runtime call to locate the block.
_Thread_local int counter = 0; // each thread gets its own 'counter' // On x86-64, reading it is roughly: // mov eax, fs:[counter@tpoff] ; fs = this thread's TLS base // Two threads incrementing 'counter' never interfere.
Each thread has its own TLS block found via the fs register; a thread-local variable is read at a fixed offset within that per-thread block.
A thread-local variable is per-thread, so it cannot be used to share data between threads, and its address is meaningful only inside the owning thread — passing &x of a thread-local to another thread is a bug. Use it for per-thread state, not communication.