Keep in mind: Don't use multiple threads unless you really, really need to, and have thought long and hard about concurrency issues.
In a way, I think the fact that many library functions are not thread-safe should be viewed as an encouragement to not use threads, or use them only for the bare minimum necessary.
I say this from a few decades of experience fighting with race conditions and the like, and whereupon several times I rewrote an existing multithreaded process into a single-threaded one and greatly improved performance and reduced memory usage. The architecture astronauts may have moved on to stuff like microservices now, but in the 90s/2000s threads were overused just as much.
That's basically impossible in many modern programming environments - even if you never spawn a thread, something else in your executable probably has. By the time your iOS or macOS app has finished launching, it has multiple threads. The Windows loader uses threads to load DLLs.
There are many ways to do multiple threads wrong. Seems that the "right way" is to wake up a sleeping but already-created thread, and take elements out of a work queue in a threadsafe way. Your main thread can even be processing elements during the 10000 clock cycles it takes to wake up a thread.
In a way, I think the fact that many library functions are not thread-safe should be viewed as an encouragement to not use threads, or use them only for the bare minimum necessary.
I say this from a few decades of experience fighting with race conditions and the like, and whereupon several times I rewrote an existing multithreaded process into a single-threaded one and greatly improved performance and reduced memory usage. The architecture astronauts may have moved on to stuff like microservices now, but in the 90s/2000s threads were overused just as much.