Ich finde, das ist ein klassischer Anwendungsfall für
TParallel.For.
Über den zurückgegeben
TLoopResult kannst du prüfen, ob alles abgearbeitet ist.
Wenn du einen eigenen
ThreadPool übergibst, kannst du mit
TThreadPool.SetMaxWorkerThreads die Anzahl gleichzeitig aktiver Tasks eingrenzen.