Права, это чрезвычайно неясная ...В Windows, что такое python launcher 'py', что позволяет control-C пересекать группы процессов?
Так на Windows, когда вы нажмете Ctrl + C, чтобы прервать программу консоли, это посылает CTRL_C_EVENT
процесс. Вы также можете сделать это вручную через GenerateConsoleCtrlEvent
. В Python, os.kill
действует как оболочка вокруг C-уровня GenerateConsoleCtrlEvent
, и позволяет нам послать CTRL_C_EVENT
к текущему процессу, выполнив:
os.kill(os.getpid(), signal.CTRL_C_EVENT)
Однако, это не просто идти на текущий процесс - это фактически относится ко всей «группе процессов», частью которой является этот процесс.
У меня есть набор тестов, который вызывает os.kill
, как вы видите выше, как часть некоторых тестов, чтобы убедиться в правильности управления C-обработкой моей программы. Однако при запуске этого набора тестов на appveyor это создает проблему, потому что, видимо, какая-то инфраструктура appveyor находится в одной и той же «группе прогресса» и разбивается.
Решение состоит в том, что нам нужно установить набор тестов с установленным флагом CREATE_NEW_PROCESS_GROUP
, так что его CTRL_C_EVENT
с не «утечка» родительского элемента. Это легко сделать. BUT ...
Если я использую CREATE_NEW_PROCESS_GROUP
и запускаю дочерний скрипт с использованием python whatever.py
, то он работает так, как ожидалось: CTRL_C_EVENT
ограничен ребенком.
Если я использую CREATE_NEW_PROCESS_GROUP
и запустить скрипт ребенка с помощью py whatever.py
(то есть, используя python launcher, который, как предполагается, эквивалентно запуску python
непосредственно), то CREATE_NEW_PROCESS_GROUP
, кажется, не имеют какой-либо эффект: CTRL_C_EVENT
влияет на родителя, как Что ж!
Вот минимальный пример программы, которая использует только os.kill
на себя, а затем проверяет, что он работал (незначительные морщины: CREATE_NEW_PROCESS_GROUP
наборы CTRL_C_EVENT
игнорируются в дочерних процессов, так что есть немного пуха здесь с помощью SetConsoleCtrlHandler
ООН-игнорировать его) : https://github.com/njsmith/appveyor-ctrl-c-test/blob/master/a.py
Вот сценарий обертки я использую для запуска выше программы: https://github.com/njsmith/appveyor-ctrl-c-test/blob/master/run-a.py
Если сценарий обертки работает python a.py
, то все работает. Если сценарий оболочки работает py a.py
, тогда сценарий оболочки получает KeyboardInterrupt
.
Так что мой вопрос: что, черт возьми, происходит здесь? Что делает пусковая установка py
по-разному от python
, что приводит к тому, что CTRL_C_EVENT
«утечка» в родительский процесс, даже если он находится в другой группе процессов? И как это возможно?
(я первоначально обнаружил это потому, что работает pytest a.py
действует как py a.py
, т.е. нарушается, но python -m pytest a.py
работы, предположительно, потому что точка входа pytest
uses the py
launcher.)
В соответствии с документацией (см. Первую ссылку в своем вопросе) вы не можете указать группу процессов при отправке сигнала CTRL + C, т. Е. 'DwProcessGroupId' всегда должен быть равен нулю, который посылает сигнал на каждый процесс которые совместно используют консоль вызывающего процесса. Так что вызов 'python' ведет себя странно, а не вызов' py'. :-) –
Да, правда. Однако это явно не то, что на самом деле происходит. Повторяя это снова, я понял, что это может объяснить это, если 'dwProcessGroupId = 0' означает отправить' CTRL_C_EVENT' все процессы на консоли, независимо от идентификатора группы процессов * и *, если вы установите 'dwProcessGroupId' в PID процесса, который * не является лидером группы, действует как установка его на 0. Тогда особая вещь о 'py' заключается в том, что мы делаем' py' лидером группы, но 'py' порождает' python' для запуска кода, поэтому 'python' не является лидером группы. –
@eryksun: моя текущая догадка заключается в том, что ошибка заключается в том, что 'GenerateConsoleCtrlEvent' обрабатывает недопустимый идентификатор группы как бы 0 (что означает« все группы »). Я согласен с тем, что способ «os.kill» обернуть его довольно запутанным, но это не проблема. –