39
__thread Foo foo;

How is foo actually resolved? Does the compiler silently replace every instance of foo with a function call? Is foo stored somewhere relative to the bottom of the stack, and the compiler stores this as "hey, for each thread, have this space near the bottom of the stack, and foo is stored as 'offset x from bottom of stack'"?

red0ct
  • 4,840
  • 3
  • 17
  • 44
anon
  • 41,035
  • 53
  • 197
  • 293

1 Answers1

49

It's a little complicated (this document explains it in great detail), but it's basically neither. Instead the compiler puts a special .tdata section in the executable, which contains all the thread-local variables. At runtime, a new data section for each thread is created with a copy of the data in the (read-only) .tdata section, and when threads are switched at runtime, the section is also switched automatically.

The end result is that __thread variables are just as fast as regular variables, and they don't take up extra stack space, either.

Dean Harding
  • 71,468
  • 13
  • 145
  • 180
  • I can see how this work if I have multi threads but only one core. When I have multi threads and multi core, how does this .tdata section work? – anon Mar 17 '10 at 03:40
  • @anon: What differences do you see in your second case? –  Mar 17 '10 at 04:55
  • time 01: core 1 runs thread 1; swaps in thread 1's .tdata; time 02: core 2 runs thread 2; swaps in thread 2's .tdata; Now isn't thread1 suddenly using thread2's .tdata? – anon Mar 17 '10 at 06:50
  • 1
    @anon: Linux threads are actually separate processes with most of their resources shared (e.g. most of their memory space), but all resources don't have to be shared; `man 2 clone` may be helpful. You can write a test program for the situation you describe. –  Mar 17 '10 at 07:18
  • 1
    How do I print out the address of .tdata that belongs to a particular thread? – anon Mar 17 '10 at 19:40
  • 3
    I don't believe you can, but the address of individual variables will be different so you can just print out the address of a single __thread variable from different threads and see that they're different. – Dean Harding Mar 17 '10 at 20:52
  • 33
    For people who are too lazy to read the attached document, the missing piece is that the address of the thread local storage region is stored in the GS segment register (FS in x86-64), so to access TLS you just do mov eax, GS:ptr. – jleahy Jan 10 '13 at 11:42
  • Also, the fs/gs register is set by the threading library using `clone` with `CLONE_SETTLS` – jrpear Oct 10 '22 at 19:31