А не надо извне закрывать потоки и процессы. Можно получить кучу неприятностей.
В нормально проработанном решении потоки/процессы сами должны закрываться тогда, когда нужно. Если нужно управлять этим извне - то для этого и существуют примитивы типа семафоров/флагов/эвентов.
В потоки полезно засовывать поиск всякий или подготовку кусочков общего решения. При этом можно использовать два шаблонных примитива: "коллектор" и "победитель":
"Коллектор":
import threading
def job(id, ...):
global res
<Подготовка блока данных>
res[id] = <блок подготовленных данных>
return
res = []
for i in range(N): # запуск N потоков
res.append(<пустой блок>)
threading.Thread(target=job, args=(i, ...)).start()
for th in threading.enumerate(): # ожидание всех потоков
if th != threading.currentThread():
th.join()
<здесь массив с блоками полностью собран >
"Победитель":
import threading
def job(...):
global val
global event
while <не нашли>
<элементарный шаг поиска>
if event.is_set():
return # кто-то уже нашел искомое
val=<то что нашли>
event.set() # этот поток нашел искомое и радостно сообщает всем об этом
return
val = None # искомое значение
event = threading.Event() # флаг сигнализирующий о том что решение найдено
threads = []
for i in range(N):
threads.append(threading.Thread(target=job, args=(i, ...)))
threads[-1].start()
event.wait() # тут основной поток ждет сигнала о победе от одного из запущенных потоков
# если есть шанс, что победителя может и не быть, то в wait() нужно указать таймаут
# и читать значение event.wait(), что бы узнать - сработал таймаут или появился победитель.
<тут обрабатываем найденное>
for th in threads: # Подчищаем за собой - гарантированно собираем закрывшиеся потоки
th.join()
ЗЫ последний цикл в "победителе" - часто не обязателен, но если сама эта процедура запущена во множестве потоков, то можно получить так называемый "потоковый потоп", когда потоки не успевают закрываться сами и плодятся в системе со страшной силой, с предсказуемыми последствиями.
ЗЫЫ также обратите внимание на варианты работы с набором потоков. В примере "Коллектор" не подразумевается, что в программе есть какие-то еще потоки, поэтому сборка потоков идет всех, кроме текущего (основного потока программы). А вот в "Победитель" потоки сохраняются в списке и из этого списка потом собираются. Это позволяет иметь в программе и другие потоки работающие в параллель с нашим поиском победителя (и в частности запускать сам такой поиск победителя в независимых потоках). Правда для оформления этого кода в отдельные потоки - возможно потребуется избавиться от глобальных переменных и работать только через передаваемые в job параметры.