Отправьте SIGINT в подпроцесс Python, используя os.kill, как если бы вы нажимали Ctrl+C
Использование Python 3.4 на Windows.
Я пытаюсь завершить дочернюю обработку, имитирующую человека, нажимающего Ctrl+C (Ctrl+D в Linux).
Я просто добавил обработчик, чтобы проверить, обрабатывается ли сигнал вообще. Я использовал идею из этого вопроса
Цель состоит в том, чтобы перехватить KeyboardInterrupt (SIGINT) и освободить ресурсы. Но, похоже, исключение не выдается, если SIGINT не приходит с клавиатуры. Вот почему я создал обработчик, но процесс, кажется, не запускает обработчик вообще...
import multiprocessing
import time
import signal
import signal
import os
import sys
def handler(signal, frame):
print("handler!!!")
sys.exit(10)
def worker():
p = multiprocessing.current_process()
try:
signal.signal(signal.SIGINT,handler)
print("[PID:{}] acquiring resources".format(p.pid))
while(True):
#working...
time.sleep(0.5)
except (KeyboardInterrupt, SystemExit):
pass
finally:
print("[PID:{}] releasing resources".format(p.pid))
if __name__ == "__main__":
lst = []
for i in range(1):
p = multiprocessing.Process(target=worker)
p.start()
lst.append(p)
time.sleep(3)
for p in lst:
os.kill(p.pid,signal.SIGINT)
p.join()
print(p)
print(p.exitcode)
print("joined all processes")
Вот пример вывода:
C:\Users\Rui>python test.py
[PID:16524] acquiring resources
<Process(Process-1, stopped[2])>
2
joined all processes
- Что я делаю неправильно?
- Должен ли я использовать модуль подпроцесса?
- Какие еще подходы я могу попытаться прервать выполнение процесса?
1 ответ
Это не работает, потому что вы не можете использовать os.kill
отправлять произвольные сигналы в Windows:
os.kill(pid, sig)
Послать сигнал sig на процессный pid. Константы для конкретных сигналов, доступных на хост-платформе, определяются в модуле сигналов.
Windows:
signal.CTRL_C_EVENT
а такжеsignal.CTRL_BREAK_EVENT
сигналы являются специальными сигналами, которые могут быть отправлены только в консольные процессы, которые имеют общее окно консоли, например, в некоторые подпроцессы. Любое другое значение дляsig
приведет к тому, что процесс будет безоговорочно убитTerminateProcess
API, и код выхода будет установлен на sig. Версия для Windowskill()
дополнительно принимает дескрипторы процесса для уничтожения.
Единственные сигналы, которые можно отправить через os.kill
являются signal.CTRL_C_EVENT
а также signal.CTRL_BREAK_EVENT
, Все остальное просто завершает процесс, что и происходит в вашем случае. С помощью signal.CTRL_C_EVENT
здесь тоже не будет работать, потому что процессы запускаются черезmultiprocessing.Process
не являются "процессами консоли, которые совместно используют общее окно консоли" с родителем. Я не уверен, что вы можете многое сделать здесь с сигналами в Windows; Не похоже, что вы можете поймать TerminateProcess
как вы можете пойматьSIGTERM
в Unix, так что вы не можете выполнить какую-либо очистку до завершения процесса, и вы не используете консольное приложение для ребенка, поэтомуsignal.*_EVENT
не сработает
Я думаю, что ваши варианты: 1) Используйте subprocess
модуль, и запустите дочерний процесс с shell=True
что, я думаю, будет означать signal.CTRL+C+EVENT
буду работать. 2) Палка сmultiprocessing
модуль, и использовать "кооперативный" метод прерывания работника, какmultiprocessing.Event
,