2016-06-17 44 views
6

Sto cercando di generare un processo Ruby on Windows utilizzando qualcosa di simile:Spawned processo Ruby on di Windows muore quando guscio è terminata

p1 = spawn('ruby', 'loop.rb', [:out, :err] => ['process.log', "w"], :new_pgroup => true) 

anche io quindi staccare dal processo tramite:

p1.detach 

Questo dovrebbe capire, per quanto mi riguarda, creare un nuovo processo indipendente dal genitore. Sto persino usando il parametro new_pgroup per assicurarmi che il nuovo processo abbia il proprio gruppo di processi.

Quando eseguo il mio script, il processo secondario inizia e continua a funzionare. Anche l'esecuzione dello script che genera il processo secondario viene completata. Tuttavia, quando ora chiudo la shell, il processo secondario muore. Mi aspetto che continui a funzionare (funziona su OS X e Linux). Non riesco a capire se si tratta di un bug nel runtime di Ruby su Windows o se si tratta di una limitazione di Windows e di come gestisce i processi.

Per completezza il codice completo Rubino di quello che sto cercando di fare:


spawner.rb: può essere eseguito tramite ruby spawner.rb e solo genera un nuovo sottoprocesso. Il processo creato è loop.rb che è solo un ciclo infinito. A seconda del sistema operativo, specifica un parametro diverso per la creazione del gruppo di processi.

require "tempfile" 
require 'rbconfig' 

class SpawnTest 

    def self.spawn_process 

    if os == :windows 
     p1 = spawn('ruby', 'loop.rb', [:out, :err] => ['process.log', "w"], :new_pgroup => true) 
    else 
     p1 = spawn('ruby', 'loop.rb', [:out, :err] => ['process.log', "w"], :pgroup => true) 
    end 

    # Detach from the processes so they will keep running 
    puts p1 
    Process.detach(p1) 
    end 

    def self.os 
    @os ||= (
    host_os = RbConfig::CONFIG['host_os'] 
    case host_os 
     when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ 
     :windows 
     when /darwin|mac os/ 
     :macosx 
     when /linux/ 
     :linux 
     when /solaris|bsd/ 
     :unix 
     else 
     raise Error::WebDriverError, "unknown os: #{host_os.inspect}" 
    end 
    ) 
    end 
end 

if __FILE__ == $0 
    SpawnTest.spawn_process 
end 

loop.rb

$stdout.sync = true 
$stderr.sync = true 

i = 0 
while i < 10000 
    $stdout.puts "Iteration #{i}" 
    sleep 1 
    i = i + 1 
end 

$stdout.puts "Bye from #{Process.pid}" 

ho trovato il win32-process gemma durante le mie indagini. Sembra che stia utilizzando le chiamate API win32 per generare processi. Qualcuno sa se questa libreria risolverebbe il problema?

Qualsiasi aiuto apprezzato.

+1

Per quello che vale, la gemma del processo win32 risolve il mio problema. Usandolo, posso creare sotto processi su Windows che non muoiono quando chiudo il terminale. Non riesco ancora a capire se il problema riscontrato con Kernel.spawn su Windows sia dovuto a un bug, opzioni errate o qualche "funzione" sconosciuta di Windows. – Hardy

+1

Puoi confermare che i processi generati vengono effettivamente creati in gruppi separati usando uno strumento come [Process Explorer] (https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx)? –

+0

Immagino tu intenda il TaskManager !? Non riesco a visualizzare il PGID lì. Vedo solo l'ID del processo. Qualche idea su come ottenere il PGID per un processo in esecuzione su Windows? Ho provato con Cygwin e 'ps -W' e posso vedere il processo e una colonna per PGID, ma è praticamente '0' per tutti i processi a prescindere. Non penso che questo risultato sia affidabile. – Hardy

risposta

2

non ho trovato alcun uso di gruppi di processi in Windows ad eccezione di dispacciamento CTRL eventi a più processi, come si afferma in Process Creation Flags MSDN docs:

gruppi di processo sono utilizzati dalla funzione GenerateConsoleCtrlEvent per consentire l'invio di un CTRL + Segnale BREAK a un gruppo di processi della console.

Cosa succede in realtà quando è specificato CREATE_NEW_PROCESS_GROUP bandiera è ...

... una chiamata implicita a SetConsoleCtrlHandler (NULL, TRUE) viene presentata per conto del nuovo processo; questo significa che il nuovo processo ha disattivato CTRL + C. Ciò consente alle shell di gestire direttamente CTRL + C e di inoltrare selettivamente quel segnale ai processi secondari. CTRL + INTERR. Non è disabilitato e può essere utilizzato per interrompere il processo/processo di gruppo.

From CreateProcess MSDN docs.

Si noti che questo non è lo stesso di chiudere la finestra della console con il pulsante x. In quest'ultimo caso il processo riceve CTRL_CLOSE_EVENT,

Un segnale che il sistema invia a tutti i processi collegati a una console quando l'utente chiude la console (sia scegliendo Chiudi menù finestra della finestra della console, oppure facendo clic sul Termina comando pulsante Task da Task Manager).

From HandlerRoutine callback MSDN docs.

La gestione di questo evento non è influenzata dal flag SetConsoleCtrlHandler(NULL,TRUE) impostato da CREATE_NEW_PROCESS_GROUP durante la creazione del processo.

Tutti sopra significa CREATE_NEW_PROCESS_GROUP flag non ha nulla a che fare con il comportamento che si sta osservando.

Per impostazione predefinita, un processo figlio inherits finestra console del genitore e maniglie IO. Pertanto, quando chiudi la shell facendo clic sul pulsante x, riceve CTRL_CLOSE_EVENT e non ha un'opzione per non terminare.

Per evitare ciò, il processo figlio non deve essere collegato alla console genitore. Questo viene fatto fornendo il flag DETACHED_PROCESS all'API di Windows CreateProcess.

Per impostazione predefinita, un processo di console eredita console del suo genitore ... processi console non sono collegati a una console se vengono creati utilizzando CreateProcess con DETACHED_PROCESS.

From Creation of a Console MSDN docs.

Questo è quello che credo che la gemma di Ruby spawn e win32-process facciano diversamente. Non ho provato a eseguire il debug di entrambi, al fine di vedere la differenza specifica nelle bandiere che forniscono a CreateProcess anche se sarebbe una cosa interessante da fare.

Esistono altri modi per creare un processo figlio senza ereditare la console o gli handle di IO del genitore. Esempi sono CREATE_NO_WINDOW o CREATE_NEW_CONSOLE bandiere, Job Objects, ecc.

+0

Wau, ottima risposta e ha molto senso. Il processo win32 ha in effetti l'opzione Process :: DETACHED_PROCESS che sto usando nel codice aggiornato. Sfortunatamente non ci sono altri flag documentati in Kernel.spawn a parte il flag: new_pgroup che si può usare per controllare la creazione del processo. Sembra una carenza/bug nella VM Ruby. O deve esporre più opzioni specifiche di Windows o impostare DETACHED_PROCESS per impostazione predefinita. Uno avrebbe bisogno di controllare l'impl reale di Kernel.spawn. Sembra che win32-process sia l'unica opzione per ora. – Hardy

+0

Bene, Ruby è principalmente popolare su piattaforme tipo Unix. Visto che il supporto di Windows non è una priorità e l'enorme differenza concettuale dell'API di Windows, direi che spawn utilizza un approccio abbastanza ragionevole quando viene invocato su Windows. Dopotutto, un processo autonomo senza finestre è disapprovato nel suo habitat a meno che non si tratti di un servizio di sistema. –

+0

Concordo sul fatto che Windows sembra un cittadino di seconda classe. Sono anche d'accordo sul fatto che nel mondo Windows un servizio di sistema probabilmente sarebbe preferito, ma questo rende le cose ancora più complicate/divergenti se si desidera scrivere codice per tutti i tipi di OS. Per quanto riguarda le impostazioni predefinite. Sembra strano offrire già dei flag specifici per Windows, ma nulla per controllare questo comportamento e se non altro la documentazione dovrebbe essere più esplicita sulle differenze. Comunque, almeno ora sappiamo :-) – Hardy