Отправьте 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приведет к тому, что процесс будет безоговорочно убит TerminateProcessAPI, и код выхода будет установлен на 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,

Другие вопросы по тегам