Threads & Concurrency Models

thread-local storage

Imagine an open-plan office where everyone shares the same big filing cabinets and supply closet — but each person also has a private locker that only they can open. Anything in the shared cabinets is visible to all; anything in your locker is yours alone, even though the locker design is identical for everyone. Thread-local storage is the private locker for threads: a variable that looks like one name in the code, but where each thread gets its own separate, private copy.

Concretely, threads share the process's global variables and heap by default, which is why two threads writing the same global can collide. A thread-local variable breaks that sharing on purpose: when a variable is declared thread-local, the system gives every thread its own independent instance of it, keyed to that thread. Thread A reading and writing the thread-local variable x touches A's copy; thread B touches B's copy; they never interfere, even though the source code refers to a single x. The runtime arranges this so that the right copy is selected automatically based on which thread is running.

Why it is useful: some state is naturally per-thread and should never be shared — a thread's own scratch buffer, its own random-number generator seed, the classic C errno (the last error code, which must be per-thread or one thread's error would clobber another's), or a per-thread cache. Putting such state in thread-local storage avoids the need for locks entirely, because there is no sharing to protect. The honest caveats: thread-local storage is not free (each thread pays the memory for its own copy, which adds up with many threads), and it is easy to misuse as a hidden global, which can make code harder to follow and to test. It solves the per-thread case cleanly, but it does not help when threads genuinely must share.

The C variable errno is thread-local: when thread A's file read fails and sets errno, thread B's errno is untouched, so each thread can check its own last error without another thread overwriting it. Without thread-local storage, errno would be a shared global and concurrent error reporting would be hopelessly scrambled.

One variable name, a private copy per thread — sharing avoided, no lock needed.

Thread-local storage removes the need for locks only because it removes the sharing — it does not help when threads truly must share data. Overusing it as a hidden global also makes code harder to test, and each thread's copy costs memory.

Also called
TLSthread-specific dataper-thread storage執行緒專屬資料