SD>Можно отстреливать по частям: перечислить созданные процессом потоки, грохнуть их TerminateThread, потом аккуратно завершить процесс с хорошим exit code.
Вот в момент 'аккуратного завершения' все и повиснет
SD>Однако TerminateThread (и TerminateProcess(self) тоже) может зависнуть, если в момент терминирования он находится внутри какой-нибудь критической секции, которая не освобождается, но затем требуется в другом потоке.
TerminateThread (и TerminateProcess( сами по себе не повиснут, ибо они — прямые вызовы сервисов ядра. Юзермодного кода в них минимум — собственно сам вызов сервиса ядра. Никаких критических секций там и в помине нету.