Я пытаюсь создать демон в Python. Я нашел следующий вопрос , в котором есть несколько полезных ресурсов, за которыми я сейчас следую, но мне любопытно, зачем нужна двойная вилка. Я покопался в гугле и нашел множество ресурсов, объявляющих, что это необходимо, но не зачем.
Некоторые упоминают, что это предотвращает приобретение демоном управляющего терминала. Как бы это сделать без второй развилки? Каковы последствия?
fork()
вызов возвращает PID дочернего элемента родителю, поэтому легко получить PID дочернего процесса, но не так просто получить PID процесса внука ).Ответы:
Глядя на код, указанный в вопросе, обоснование:
Таким образом, он должен гарантировать, что демон заново переименован в init (на случай, если процесс, запускающий демона, является долгоживущим), и исключает любые шансы демона на повторный захват управляющего tty. Так что, если ни один из этих случаев не применим, то одной вилки должно быть достаточно. " Сетевое программирование Unix - Стивенс " имеет хороший раздел на эту тему.
источник
p=fork(); if(p) exit(); setsid()
. В этом случае родитель также выходит, и первый дочерний процесс переопределяется. Магия двойных вилок требуется только для предотвращения приобретения демона tty.forks
будетchild
запущен процесс, этот самый первый дочерний процесс будетsession leader
и сможет открыть терминал TTY. Но если я снова отключусь от этого потомка и прерву этого первого потомка, второй раздвоенный потомок не будетsession leader
и не сможет открыть терминал TTY. Это утверждение правильно?setsid()
. Таким образом, первый разветвленный процесс становится лидером сеанса после вызова,setsid()
а затем мы снова выполняем ветвление, так что последний, разветвленный процесс больше не является лидером сеанса. Помимо требованияsetsid()
быть лидером сессии, вы на месте.Я пытался понять двойную вилку и наткнулся на этот вопрос здесь. После долгих исследований это то, что я понял. Надеюсь, это поможет прояснить ситуацию для тех, у кого такой же вопрос.
В Unix каждый процесс принадлежит группе, которая, в свою очередь, принадлежит сеансу. Вот иерархия ...
Сеанс (SID) → Группа процессов (PGID) → Процесс (PID)
Первый процесс в группе процессов становится лидером группы процессов, а первый процесс в сеансе становится лидером сеанса. С каждым сеансом может быть связан один TTY. Только лидер сеанса может взять под контроль TTY. Для того, чтобы процесс был по-настоящему демонизирован (запущен в фоновом режиме), мы должны убедиться, что лидер сеанса убит, чтобы исключить возможность того, что сеанс когда-либо получит контроль над TTY.
Я запустил программу-демон Сандера Маречала на Python с этого сайта на моем Ubuntu. Вот результаты с моими комментариями.
Обратите внимание, что процесс является лидером сеанса после
Decouple#1
, потому что этоPID = SID
. Это все еще может взять под контроль TTY.Обратите внимание, что
Fork#2
больше не является лидером сессииPID != SID
. Этот процесс никогда не может взять под контроль TTY. Истинно демонизирован.Лично я нахожу терминологическую форк-двойку непонятной. Лучшей идиомой может быть вилка-развязка-вилка.
Дополнительные ссылки, представляющие интерес:
источник
fork()
уже предотвращает создание зомби, при условии, что вы закроете родителя.setsid()
перед сингломfork()
? На самом деле я думаю, что ответы на этот вопрос ответят на это.Строго говоря, двойная вилка не имеет ничего общего с повторным воспитанием демона как потомка
init
. Все, что необходимо для повторного воспитания ребенка, это то, что родитель должен выйти. Это может быть сделано только с одной вилкой. Кроме того, двойное разветвление само по себе не переопределяет процесс демонаinit
; родитель демона должен выйти. Другими словами, родитель всегда выходит, когда разветвляет правильного демона, чтобы процесс демона был переназначенinit
.Так почему двойная вилка? POSIX.1-2008 Раздел 11.1.3, « Терминал управления », содержит ответ (выделение добавлено):
Это говорит нам о том, что если процесс-демон делает что-то вроде этого ...
... тогда процесс-демон может быть выбран в
/dev/console
качестве управляющего терминала в зависимости от того, является ли процесс-демон лидером сеанса, и в зависимости от реализации системы. Программа может гарантировать, что вышеуказанный вызов не получит управляющий терминал, если программа сначала гарантирует, что он не является лидером сеанса.Обычно при запуске демона
setsid
вызывается (от дочернего процесса после вызоваfork
), чтобы отделить демон от его управляющего терминала. Однако вызовsetsid
также означает, что вызывающий процесс будет лидером сеанса нового сеанса, что оставляет открытой возможность того, что демон может повторно захватить управляющий терминал. Метод двойного разветвления гарантирует, что процесс-демон не является лидером сеанса, что затем гарантирует, что вызовopen
, как в примере выше, не приведет к тому, что процесс-демон повторно запросит управляющий терминал.Техника двойной вилки немного параноидальна. В этом нет необходимости, если вы знаете, что демон никогда не откроет файл терминального устройства. Кроме того, в некоторых системах это может не потребоваться, даже если демон действительно открывает файл оконечного устройства, поскольку такое поведение определяется реализацией. Однако одна вещь, которая не определяется реализацией, состоит в том, что только лидер сеанса может выделить управляющий терминал. Если процесс не является лидером сеанса, он не может выделить управляющий терминал. Поэтому, если вы хотите быть параноиком и быть уверенным, что процесс-демон не может случайно получить управляющий терминал, независимо от специфики, определенной реализацией, тогда метод двойного разветвления является существенным.
источник
LogFile=/dev/console
. Программы не всегда имеют контроль во время компиляции над тем, какие файлы они могут открывать;)Взято из Bad CTK :
«В некоторых разновидностях Unix вы вынуждены делать двойную форк при запуске, чтобы перейти в режим демона. Это потому, что одноразовое разветвление не гарантирует отсоединение от управляющего терминала».
источник
setsid
после начальной форка. Затем он гарантирует, что он остается отсоединенным от управляющего терминала, снова разветвляясь и имея выход лидера сеанса (вызывающий процессsetsid
).fork
том, что он отсоединяется от управляющего терминала. Это то,setsid
что делает это. Ноsetsid
потерпит неудачу, если он будет вызван руководителем группы процессов. Поэтому сначалаfork
необходимо выполнить инициализацию,setsid
чтобы обеспечитьsetsid
вызов из процесса, который не является лидером группы процессов. Второйfork
гарантирует, что конечный процесс (тот, который будет демоном) не является лидером сеанса. Только лидеры сеансов могут получить управляющий терминал, поэтому этот второй ответвление гарантирует, что демон не получит непреднамеренный запрос управляющего терминала. Это верно для любой POSIX OS.Согласно «Расширенному программированию в среде Unix» Стивенса и Раго, второй ответвление является скорее рекомендацией, и оно сделано для того, чтобы гарантировать, что демон не получит управляющий терминал в системах на основе System V.
источник
Одна из причин заключается в том, что родительский процесс может немедленно поднять wait_pid () для потомка, а затем забыть об этом. Когда потом умирает внучка, его родителем является init, и он будет ждать () этого - и выводит его из состояния зомби.
В результате родительский процесс не должен знать о разветвленных дочерних элементах, а также позволяет разветвлять долго выполняющиеся процессы из библиотек и т. Д.
источник
Вызов daemon () имеет родительский вызов _exit () в случае успеха. Первоначальная мотивация, возможно, заключалась в том, чтобы позволить родителю выполнять дополнительную работу, пока ребенок демонизирует.
Это также может быть основано на ошибочном убеждении, что это необходимо для того, чтобы у демона не было родительского процесса и он был переименован в init - но это произойдет в любом случае, когда родитель умирает в случае с одним форком.
Так что я полагаю, что в конце концов все сводится к традиции - достаточно одной развилки, если родитель все равно умрет в коротком порядке.
источник
Достойное обсуждение этого, кажется, находится на http://www.developerweb.net/forum/showthread.php?t=3025
Цитирую Млампкина оттуда:
источник
Это может быть легче понять следующим образом:
источник