Зарегистрированный обработчик atexit унаследован порожденными дочерними процессами - PullRequest
2 голосов
/ 27 июня 2009

Я пишу программу-демон, использующую python 2.5. В основном процессе обработчик выхода регистрируется в модуле atexit, кажется , что этот обработчик вызывается при завершении каждого дочернего процесса, чего я не ожидал.

Я заметил, что это поведение не упоминается в python atexit doc, кто-нибудь знает проблему? Если это так, как я должен вести себя, как я могу отменить регистрацию обработчика выхода в дочерних процессах? В версии 3.0 есть atexit.unregister, но я использую 2.5.

Ответы [ 3 ]

3 голосов
/ 27 июня 2009

Когда вы fork делаете дочерний процесс, этот дочерний объект является точной копией родительского процесса - включая, конечно, зарегистрированные функции выхода, а также весь другой код и структуры данных. Я полагаю, что это проблема, которую вы наблюдаете - конечно, она не упоминается в каждом модуле, потому что она обязательно относится к каждому.

3 голосов
/ 30 июня 2009

В Python 2.5 нет API для этого, но вы можете просто:

import atexit
atexit._exithandlers = []

в ваших дочерних процессах - если вы знаете, что у вас установлен только один обработчик выхода, а другие обработчики не установлены. Однако следует помнить, что некоторые части stdlib (например, logging) регистрируют обработчики atexit. Чтобы не попирать их, вы можете попробовать:

my_handler_entries = [e for e in atexit._exithandlers if e[0] == my_handler_func]
for e in my_handler_entries:
    atexit._exithandlers.remove(e)

где my_handler_func - обработчик atexit, который вы зарегистрировали, и это должно удалить вашу запись, не удаляя другие.

1 голос
/ 27 июня 2009

atexit.register() в основном регистрирует вашу функцию в atexit._exithandlers, который является частным списком функций модуля, вызываемых sys.exitfunc(). Вы можете установить exitfunc() в свою собственную функцию обработчика выхода, которая затем проверяет дочерний статус или просто отменяет его регистрацию. Как насчет того, чтобы просто скопировать 3.0 atexit.py в ваше локальное дерево исходников и использовать его вместо этого?

РЕДАКТИРОВАТЬ: я скопировал atexit.py из моей версии 2.6 и расширил его на

def unregister(func, *targs, **kargs):
    _exithandlers.remove((func, targs, kargs))

Если вы возьмете это вместо оригинальной версии, оно должно работать. Я не проверял это с подпроцессами, хотя.

...