4 ms·
Why aren't thread-local constructors called when the thread is created rather than doing a test on every variable access? Perhaps they wanted to have the OS-nat
by alexvitkov 2y ago
Why aren't thread-local constructors called when the thread is created rather than doing a test on every variable access? Perhaps they wanted to have the OS-native pthread_create/CreateThread "work out of the box" without having to manually call `construct_thread_locals()` or whatever? That would be an insane tradeoff, especially considering `construct_thread_locals()` can be called automatically when using std::thread.
- pjc50 2y agoI think this, and all the other weirdness, is because usage of thread-local variables is pretty low. Probably somebody wanted to have "lightweight" threads doing work as quickly as possible accessing only local variables. Edit: ah, see https://www.akkadia.org/drepper/tls.pdf https://www.akkadia.org/drepper/tls.pdf which I was clued into by https://news.ycombinator.com/item?id=43079061 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.
- alexvitkov 2y agoI don't buy the static linking part - we already generate a single function in the linked binary that calls all static constructors from all translation units, the same thing can be done for TLS constructors (what I called construct_thread_locals() in parent), and force the user to call that manually on thread creation, or call it as part of std::thread. 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.
- comex 2y agoThe problem is that dynamic linking is the norm. If you're writing a specific application, that's one thing. But if you're writing some random C++ library then you usually have no idea whether it will be compiled into an executable or a shared library. If TLS is slow in either of those cases, then the only solution is to not use TLS at all.
- yuliyp 2y agoBecause that can be very expensive. If you spawn a thread which does a little work and exits, having that also first need to initialize every thread local from every loaded library on the off chance that it might need that thread local would probably be not worth it.
- alexvitkov 2y agoCreating a thread is already very expensive, in a sane program your ten TLS constructors shouldn't come even close to the amount of bookkeeping that the kernel has to do to spin up a new thread. 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.
- dzaima 2y agoIn a simple benchmark, creating a thread & waiting on it in a loop (pthread_create+pthread_join) takes 0.03ms = 30000ns, so running a bunch of constructors of a bunch of libraries could actually be a non-insignificant amount of 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)
- surajrmal 2y agoIf you make use of dynamic linking namespaces and some sort of runtime, you can make it impossible to enter specific libraries in certain libraries in certain threads and avoid that cost. If your application is large enough that you can't keep track of deps, then you may want something like that in your application if you're not willing to split it into multiple processes.
- 2y ago