Edit: ah, see https://www.akkadia.org/drepper/tls.pdf which I was clued into by https://news.ycombinator.com/item?id=43079061
The situation is much more complicated than it sounds, because the question of where the variables are isn't known at compile time. It has to be done at link time. Which may include dynamic link time as a library is loaded. That all sounds fairly horrible.
All to handle static constructors. If you don't have thread-static variables, or they don't have constructors, it's much simpler.
Dynamic linking is a whole other beast, and maybe for thread_local's in a DLL it's acceptable (or the only possible way?) to do construct them lazily - if you're using DLL+TLS+global constructors you deserve the pain.
Also creating a thread, doing little work and exiting immediately is a bad use of threads -- I don't think that everyone using thread_local should be punished to better support poorly written programs. Most threads are long-running and most programs spin up a bunch of worker threads at initialization time, I'd argue variable access time is way more important than thread startup time.
Do agree that threadlocal read speed should be a lot more important, but it'd quite suck if the "acceptable performance" thread usage approaches would vary dramatically depending on what libraries you've (or something else) has unrelatedly loaded. (though maybe other overheads might appear from other sources similarly, keeping this not the most important slowdown, idk)
This is not true, at least on Linux. With appropriate settings (e.g. a small stack) thread creation can be extremely cheap.