В чем причина выполнения двойной вилки при создании демона?
Я пытаюсь создать демона в python. Я нашел следующий вопрос, в котором есть некоторые хорошие ресурсы, которые я в настоящее время следую, но мне любопытно, почему необходима двойная вилка. Я поцарапал вокруг google и нашел много ресурсов, объявляющих, что один необходим, но не почему.
некоторые упоминают, что это должно предотвратить демон от приобретения управляющего терминала. Как бы он это сделал без второй вилки? Каковы последствия?
9 ответов:
глядя на код, указанный в вопросе, оправдание-это:
# Fork a second child and exit immediately to prevent zombies. This # causes the second child process to be orphaned, making the init # process responsible for its cleanup. And, since the first child is # a session leader without a controlling terminal, it's possible for # it to acquire one by opening a terminal in the future (System V- # based systems). This second fork guarantees that the child is no # longer a session leader, preventing the daemon from ever acquiring # a controlling terminal.таким образом, это должно гарантировать, что демон повторно воспитывается на init (на всякий случай, если процесс запуска демона долго живет) и удаляет любую возможность повторного получения демоном управляющего tty. Поэтому, если ни один из этих случаев не применяется, то одной вилки должно быть достаточно. "Unix Network Programming-Stevens " есть хороший раздел по этому поводу.
Я пытался понять двойную вилку и наткнулся на этот вопрос здесь. После долгих исследований это то, что я понял. Надеюсь, это поможет прояснить ситуацию лучше для тех, кто имеет тот же вопрос.
в Unix каждый процесс принадлежит к группе, которая в свою очередь принадлежит к сессии. Вот такая иерархия...
Session (SID) → Process Group (PGID) → Process (PID)
первый процесс в группе процессов становится группой процессов лидер и первый процесс становится лидером сессии. Каждый сеанс может иметь один TTY, связанный с ним. Только руководитель сеанса может взять под контроль TTY. Чтобы процесс был по-настоящему демонизирован (запущен в фоновом режиме), мы должны гарантировать, что лидер сеанса будет убит, чтобы не было возможности сеанса когда-либо взять под контроль TTY.
я запустил программу демона примера python Sander Marechal из этот сайт на моем Ubuntu. Вот такие результаты с моими комментариями.
1. `Parent` = PID: 28084, PGID: 28084, SID: 28046 2. `Fork#1` = PID: 28085, PGID: 28084, SID: 28046 3. `Decouple#1`= PID: 28085, PGID: 28085, SID: 28085 4. `Fork#2` = PID: 28086, PGID: 28085, SID: 28085обратите внимание, что процесс является лидером сеанса после
Decouple#1, потому чтоPID = SID. Он все еще мог взять под контроль TTY.отметим, что
Fork#2больше не является лидером сессииPID != SID. Этот процесс никогда не может взять под контроль TTY. действительно демонизированной.я лично нахожу терминологическую вилку-дважды запутанной. Лучшей идиомой может быть вилка-развязка-вилка.
Дополнительные ссылки интерес:
- Unix процессы -http://www.win.tue.nl / ~aeb/linux/lk/lk-10.html
строго говоря, двойная вилка не имеет ничего общего с повторным воспитанием демона как ребенка
init. Все, что необходимо для повторного родителя ребенка является то, что родитель должен выйти. Это можно сделать только с одной вилкой. Кроме того, выполнение двойной вилки само по себе не приводит к повторному родительству процесса демона кinit; родитель демона должны выход. Другими словами, родитель всегда завершает работу при разветвлении соответствующего демона, чтобы процесс демона был повторно родительскимinit.так почему же двойная вилка? POSIX.1-2008 11.1.3, "Управляющий Терминал", был ответ (Курсив мой):
управляющий терминал для сеанса составляет выделено руководителем сессии в реализации определенным способом. Если лидер сеанса не имеет управляющего терминала и открывает файл терминального устройства, который еще не связан с сеансом, без использования параметра O_NOCTTY (см. open ()), определяется реализация, становится ли терминал управляющим терминалом лидера сеанса. Если процесс, который является не лидер сессии открывает файл терминала, или параметр O_NOCTTY используется в open (),тогда этот терминал не должен становиться управляющим терминалом вызывающего процесса.
это говорит нам, что если демон сделает что-то подобное ...
int fd = open("/dev/console", O_RDWR);... затем демон процесс может приобрести
/dev/consoleв качестве управляющего терминала, в зависимости от того, является ли процесс демона лидером сеанса, и в зависимости от реализации системы. Программа может гарантия что вышеупомянутый вызов не получит управляющий терминал, если программа сначала гарантирует, что он не является лидером сеанса.обычно, при запуске демона,
setsidвызывается (из дочернего процесса после вызоваfork), чтобы отделить демона от своего управляющего терминала. Однако, вызовsetsidтакже означает, что вызывающий процесс будет лидером сеанса нового сеанса, что оставляет открытой возможность того, что демон может повторно получить управляющий терминал. Метод двойной вилки гарантирует, что процесс демона не является лидером сеанса, который затем гарантирует, что вызовopen, как и в приведенном выше примере, не приведет к тому, что процесс демона повторно получит управляющий терминал.двойная вилка техника немного параноидальная. Это может быть не нужно, если вы знаю что демон никогда не откроет файл терминального устройства. Кроме того, в некоторых системах это может быть не нужно, даже если демон открывает файл терминального устройства, так как это поведение определяется реализацией. Однако одна вещь, которая не определена реализацией, заключается в том, что только лидер сеанса может выделить управляющий терминал. если процесс не является лидером сеанса, он не может выделить элемент управления терминал.
принято от Bad CTK:
" на некоторых вариантах Unix вы вынуждены делать двойную вилку при запуске, чтобы перейти в режим демона. Это потому, что один разветвление не гарантируется для отключения от управляющего терминала."
согласно "Advanced Programming in the Unix Environment", Стивенс и Раго, вторая вилка является скорее рекомендацией, и это делается для того, чтобы гарантировать, что демон не приобретает управляющий терминал в системах на основе System V.
одна из причин заключается в том, что родительский процесс может сразу wait_pid() для ребенка, а потом забыть об этом. Когда тогда умирает внук, его родитель находится в init, и он будет ждать() для него - и выводит его из состояния зомби.
в результате родительский процесс не должен быть осведомлен о разветвленных дочерних элементах, а также позволяет разветвлять длительные запущенные процессы из библиотек и т. д.
вызов daemon() имеет Родительский вызов _exit (), если он выполняется успешно. Первоначальная мотивация, возможно, заключалась в том, чтобы позволить родителю выполнять дополнительную работу, пока ребенок демонизирует.
Это также может быть основано на ошибочном убеждении, что это необходимо для того, чтобы демон не имел родительского процесса и был переориентирован на init - но это произойдет в любом случае, как только родитель умрет в одном случае вилки.
Так что я полагаю, что все это просто сводится к традиции в конце - а одной вилки достаточно до тех пор, пока родитель умирает в короткие сроки в любом случае.
приличное обсуждение этого, кажется, в http://www.developerweb.net/forum/showthread.php?t=3025
цитируя оттуда млампкина:
...подумайте о вызове setsid () как о "новом" способе сделать что-то (отсоединиться от терминала ) и вызове [second] fork () после него как избыточность для работы с SVr4...
Это может быть проще понять таким образом:
- первая вилка и setsid создадут новый сеанс (но идентификатор процесса == идентификатор сеанса).
- вторая вилка гарантирует идентификатор процесса != идентификатор сеанса.
Comments