Use condition variables to signal the threads to break out of the loop, clean up, and terminate on their own, then have the main thread wait for each of them.
Killing a thread is the first thing that comes to mind when one is first starting with threading, but you should really only do it when there's no other choice.
Besides condition variables, you can a synchronized message queue that is shared among all the threads. When request come into parent thread, parent thread put the request on the queue and the child thread will pick them up. Likewise in order to terminate, parent thread put TERMINATE requests on the message queue and let the child threads pick them up and terminate one by one on their own. Parent thread need to keep track on the number of child threads it spawns so all child receive the TERMINATE requests. The number is also for parent thread to know the total number of child threads that terminated normally else may need a force-kill of that child (this is last resort).
There are other ways but the general idea should be the same. Parent thread need to 'signal' or find a way to communicate with their child it is time to TERMINATE. The communication mechanism can be condition variables, synchronized message queue and etc etc.