Как запустить и забыть подпроцесс?

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

Мне удалось сделать то, что мне нужно, зачеркнув какой-то код из книги "Программирование рубинов", но я хотел бы найти лучший/правильный способ и понять, что происходит. Вот что я получил изначально:

exec("whatever --take-very-long") if fork.nil?
Process.detach($$)


Итак, так ли это или как мне это сделать?

После проверки ответов ниже я закончил с этим кодом, который, кажется, имеет больше смысла:

(pid = fork) ? Process.detach(pid) : exec("foo")


Буду признателен за то, как работает fork. [получил это уже]

Правильно ли отсоединение $$? Я не знаю, почему это работает, и мне очень хотелось бы лучше понять ситуацию.

Ответ 1

Функция fork разделяет ваш процесс на два.

Оба процесса затем получают результат функции. Ребенок получает значение zero/ nil (и, следовательно, знает, что он является дочерним), а родитель получает PID дочернего элемента.

Следовательно:

exec("something") if fork.nil?

приведет к тому, что дочерний процесс начнет "что-то", и родительский процесс будет продолжен там, где он был.

Обратите внимание, что exec() заменяет текущий процесс "чем-то", поэтому дочерний процесс никогда не будет выполнять какой-либо последующий код Ruby.

Вызов Process.detach() выглядит как неправильный. Я бы ожидал, что у него будет дочерний PID, но если я правильно прочитаю ваш код, он фактически отменит родительский процесс.

Ответ 2

Альнитак прав. Здесь более явный способ написать его, без $$

pid = Process.fork
if pid.nil? then
  # In child
  exec "whatever --take-very-long"
else
  # In parent
  Process.detach(pid)
end

Цель отсоединения - просто сказать: "Мне все равно, когда ребенок заканчивается", чтобы избежать процессов зомби.

Ответ 3

Отсоединение $$ было неправильным. С. 348 Пикакса (2-е изд.):

$$ Fixnum Номер процесса выполняемой программы. [r/o]

Этот раздел "Переменные и константы" в главе "Язык Ruby" очень удобен для декодирования различных констант ruby ​​short $, однако онлайн-версия (первая

Итак, что вы на самом деле делали, это отделить программу от себя, а не от ее ребенка. Как говорили другие, надлежащим способом отсоединиться от ребенка является использование дочернего pid, возвращенного из fork().

Ответ 4

Другие ответы хороши, если вы уверены, что хотите отделить дочерний процесс. Однако, если вы либо не возражаете, либо предпочтете, чтобы дочерний процесс был присоединен (например, вы запускаете под-серверы/службы для веб-приложения), вы можете воспользоваться следующей стенографией

fork do
    exec('whatever --option-flag')
end

Предоставление блока сообщает fork выполнить этот блок (и только тот блок) в дочернем процессе, продолжая в родительском.

Ответ 5

Я нашел ответы выше сломал мой терминал и испортил выход. это решение, которое я нашел.

   system("nohup ./test.sh &")

на всякий случай, если кто-то имеет такую ​​же проблему, моя цель состояла в том, чтобы войти в ssh-сервер, а затем сохранить этот процесс на неопределенный срок. поэтому test.sh это

#!/usr/bin/expect -f
spawn ssh host -l admin -i cloudkey  
expect "pass"
send "superpass\r"
sleep 1000000