Python запускает дочерний подпроцесс, отсоединяется и выезжает

Мне интересно, правильно ли это выполнить системный процесс и отсоединиться от родителя, хотя он позволяет родителям выйти без создания зомби и/или убить дочерний процесс. В настоящее время я использую модуль подпроцесса и делаю это...

os.setsid() 
os.umask(0) 
p = subprocess.Popen(['nc', '-l', '8888'],
                     cwd=self.home,
                     stdout=subprocess.PIPE, 
                     stderr=subprocess.STDOUT)

os.setsid() изменяет группу процессов, которая, как мне кажется, позволяет продолжить процесс, когда он выйдет из родителя, поскольку он больше не принадлежит к той же группе процессов.

Является ли это правильным, а также является ли это надежным способом выполнения этого?

В принципе, у меня есть утилита удаленного управления, которая обменивается данными через сокеты и позволяет запускать процессы удаленно, но я должен убедиться, что если пульт дистанционного управления умирает, запущенные процессы продолжают работать без изменений.

Я читал о двойных вилках и не уверен, что это необходимо и/или подпроцесс .POpen close_fds как-то позаботится об этом, и все, что нужно, - это изменить группу процессов?

Спасибо.

Илья

Ответы

Ответ 1

popen в Unix выполняется с помощью fork. Это означает, что вы будете в безопасности с:

  1. вы запускаете Popen в родительском процессе
  2. немедленно выйти из родительского процесса

Когда родительский процесс завершается, дочерний процесс наследуется процессом init (launchd в OSX) и будет по-прежнему выполняться в фоновом режиме.

Первые две строки вашей программы на Python не нужны, это прекрасно работает:

import subprocess
p = subprocess.Popen(['nc', '-l', '8888'],
                     cwd="/",
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT)

Я читал о двойных вилках и не уверен, что это необходимо

Это понадобится, если ваш родительский процесс продолжает работать, и вам нужно защитить своих детей от смерти с родителем. Этот ответ показывает, как это можно сделать.

Как работает двойная вилка:

  1. создать ребенка с помощью os.fork()
  2. в этом дочернем вызове Popen(), который запускает длительный процесс
  3. дочерний выход: процесс Popen наследуется init и выполняется в фоновом режиме

Почему родитель должен немедленно выйти? Что произойдет, если он не выйдет сразу?

Если вы оставляете родителя работающим, а пользователь останавливает процесс, например, через ctrl-C (SIGINT) или ctrl-\ (SIGQUIT), тогда он уничтожит как родительский процесс, так и процесс Popen.

Что если он выходит через секунду после разветвления?

Затем, в течение этого периода 1 с, ваш процесс Popen уязвим к ctrl-c и т.д. Если вам нужно быть на 100% уверенным, используйте двойное разветвление.