Como disparar e esquecer um subprocesso?
Pergunta
Eu tenho um processo de longa duração e eu preciso dele para lançar outro processo (que será executado por um bom tempo também). Eu preciso começar a ele só, e depois esquecer-se completamente sobre isso.
Eu consegui fazer o que eu precisava escavando algum código a partir do livro de Ruby programação, mas eu gostaria de encontrar a melhor maneira / direita, e entender o que está acontecendo. Aqui está o que eu tenho inicialmente:
exec("whatever --take-very-long") if fork.nil?
Process.detach($$)
Então, este é o caminho, ou que outra forma eu deveria fazê-lo?
Depois de verificar as respostas abaixo eu acabei com este código, o que parece fazer mais sentido:
(pid = fork) ? Process.detach(pid) : exec("foo")
Eu apreciaria uma explicação sobre como fork
funciona. [Tenho que já]
Foi destacando $$
certo? Eu não sei por que isso funciona, e eu realmente adoraria ter uma melhor compreensão da situação.
Solução
A função fork
separa o seu processo em dois.
Ambos processos, em seguida, receber o resultado da função. A criança recebe um valor de zero / nil
(e, portanto, sabe que é a criança) e o pai recebe o PID da criança.
Assim:
exec("something") if fork.nil?
fará com que o processo filho começar "algo", e o processo pai vai continuar com onde estava.
Note que exec()
substitui o processo atual com "algo", de modo que o processo filho nunca vai executar qualquer código Ruby posterior.
A chamada para olhares Process.detach()
como ele pode estar incorreta. Eu teria esperado que ele tenha PID da criança nele, mas se eu ler o seu código de direito é realmente desanexar o processo pai.
Outras dicas
Alnitak é certo. Aqui está uma forma mais explícita para escrevê-lo, sem $$
pid = Process.fork
if pid.nil? then
# In child
exec "whatever --take-very-long"
else
# In parent
Process.detach(pid)
end
O objetivo da desconexão é apenas para dizer: "Eu não me importo quando a criança termina" para evitar zombie processa .
Detaching $$
não estava certo. De p. 348 da picareta (2ª Ed):
$$
Fixnum O número do processo do programa que está sendo executado. [R / o]
Esta seção, "Variáveis ??e Constantes" no capítulo "Ruby Language", é muito útil para a descodificação de várias constantes $
curtas rubi - no entanto, a edição on-line (o primeiro
Então, o que você estava realmente fazendo era destacar o programa de si mesmo, não de seu filho.
Como já foi dito, a maneira correta de separar a criança é usar pid da criança voltou de fork()
.
As outras respostas são bons, se você tem certeza que deseja desanexar o processo filho. No entanto, se você não quer se importa, ou prefere manter o processo filho anexado (por exemplo, você está lançando sub-servidores / serviços para um aplicativo web), então você pode tirar proveito da seguinte atalho
fork do
exec('whatever --option-flag')
end
Proporcionar um bloco diz garfo para executar esse bloco (e somente esse bloco) no processo filho, enquanto continua em no pai.
i encontrou as respostas acima quebrou meu terminal e errei a saída. esta é a solução que eu encontrei.
system("nohup ./test.sh &")
apenas no caso de alguém tem o mesmo problema, meu objetivo era entrar em um servidor ssh e depois manter esse processo funcionando indefinidamente. assim test.sh é este
#!/usr/bin/expect -f
spawn ssh host -l admin -i cloudkey
expect "pass"
send "superpass\r"
sleep 1000000