The task_scheduler_init object controls number of worker threads. Yes, this number is not changed until the object is destruted. But actual concurrency level is not total number of worker thread, but number of threads active at the moment.
E.g. if machine is 8 core, task_scheduler_init creates 7 worker threads (one core is left for the master thread). This is default value and may be changed by developer. Even if CPU is busy by any other threads and applications, there will be created 7 thread. Some of them will execute, if they have tasks and CPU resource from OS. Some will wait inactively.
Number of currently executed threads is changed dynamically. It adopts tochanges in CPU availabilitydynamically the similar way you're talking about. This is because of task based parallelism, so tasks can be load-balanced between workers. It's not needed to create and remove workers each time, it's enough to make some of them inactive, if CPU is busy by others. Having some threads in waiting state doesn't give much overhead.
So it works almost the same way you described.