OpenMP thread-pools for its Pragmas (also here and here). Spinning up and tearing down threads is expensive. OpenMP avoids this overhead, so all it’s doing is the actual work and the minimal shared-memory shuttling of the execution state. In your Threads
code you are spinning up and tearing down a new set of 16 threads every iteration.