2016-06-17 10 views
6

Ich versuche, einen Ruby-Prozess auf Windows, um laichen so etwas wie dies mit:Spawned Ruby-Prozess auf Windows stirbt, wenn Shell beendet wird

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

Ich löse auch dann aus dem Verfahren über:

p1.detach 

Das sollte, soweit ich weiß, einen neuen Prozess schaffen, der unabhängig vom Elternteil ist. Ich verwende sogar den Parameter new_pgroup, um sicherzustellen, dass der neue Prozess seine eigene Prozessgruppe erhält.

Wenn ich mein Skript ausführe, wird der Unterprozess gestartet und läuft weiter. Die Ausführung des Skripts, das den Unterprozess hervorbringt, ist ebenfalls abgeschlossen. Wenn ich nun die Shell schließe, stirbt der Subprozess ab. Ich würde erwarten, dass es weiter läuft (unter OS X und Linux). Ich kann nicht herausfinden, ob dies ein Fehler in der Ruby-Laufzeit unter Windows ist oder ob dies eine Einschränkung von Windows ist und wie es Prozesse verarbeitet.

Der Vollständigkeit der vollständige Ruby-Code von dem, was ich zu tun versucht:


spawner.rb: über ruby spawner.rb ausgeführt werden und laicht gerade einen neuen Teilprozess. Der Prozess erstellt loop.rb, die nur eine Endlosschleife ist. Je nach Betriebssystem gibt es einen anderen Parameter für die Erstellung der Prozessgruppe an.

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}" 

fand ich die win32-process gem während meiner Untersuchungen. Es scheint Win32-API-Aufrufe zu verwenden, um Prozesse zu spawnen. Weiß jemand, ob diese Bibliothek das Problem beheben würde?

Jede Hilfe wird geschätzt.

+1

Für was es wert ist, löst der win32-Prozess Edelstein mein Problem. Damit kann ich unter Windows Unterprozesse erstellen, die beim Schließen des Terminals nicht abstürzen. Ich weiß immer noch nicht, ob das Problem, das ich mit Kernel.spawn unter Windows sehe, auf einen Fehler, falsche Optionen oder ein mir unbekanntes "Feature" von Windows zurückzuführen ist. – Hardy

+1

Können Sie bestätigen, dass die erstellten Prozesse tatsächlich in separaten Gruppen mit einem Tool wie [Process Explorer] (https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx) erstellt wurden? –

+0

Ich nehme an, du meinst den TaskManager !? Ich kann die PGID dort nicht sehen. Ich sehe nur die Prozess-ID. Irgendeine Idee, wie man die PGID für einen laufenden Prozess unter Windows bekommt? Ich habe mit Cygwin und 'ps -W' versucht und ich kann den Prozess und eine Spalte für PGID sehen, aber es ist ziemlich viel '0' für alle Prozesse unabhängig. Ich glaube nicht, dass diese Ausgabe zuverlässig ist. – Hardy

Antwort

2

ich keine Verwendung von Prozessgruppen in Windows mit Ausnahme Dispatching CTRL Ereignisse an mehrere Prozesse finden konnten, wie es in Process Creation Flags MSDN docs heißt es:

Prozessgruppen durch die GenerateConsoleCtrlEvent Funktion verwendet werden, zu ermöglichen, eine CTRL das Senden + BREAK-Signal an eine Gruppe von Konsolenprozessen.

Was tatsächlich passiert, wenn CREATE_NEW_PROCESS_GROUP Flag angegeben wird, ist ...

... ein impliziter Aufruf SetConsoleCtrlHandler (NULL, TRUE) im Namen des neuen Verfahrens hergestellt wird; Dies bedeutet, dass der neue Prozess STRG + C deaktiviert hat. Dadurch können Shells STRG + C selbst behandeln und dieses Signal selektiv an Unterprozesse weiterleiten. STRG + UNTBR ist nicht deaktiviert und kann verwendet werden, um die Prozess-/Prozessgruppe zu unterbrechen.

From CreateProcess MSDN docs.

Beachten Sie, dass dies nicht das Schließen des Konsolenfensters mit der Schaltfläche x ist. Im letzteren Fall wird der Prozess CTRL_CLOSE_EVENT,

ein Signal empfängt, dass das System an alle Prozesse an einer Konsole befestigt sendet, wenn der Benutzer die Konsole schließt (entweder durch Schließen Klicken auf das Fenstermenü der Konsolenfenster oder durch das Klicken Taskschaltflächenbefehl aus Task-Manager beenden).

From HandlerRoutine callback MSDN docs.

Die Verarbeitung dieses Ereignisses wird durch Flag bei der Erstellung des Prozesses nicht beeinflusst.

Alles oben bedeutet CREATE_NEW_PROCESS_GROUP Flag hat nichts mit dem Verhalten zu tun, das Sie beobachten.

Standardmäßig ein Kind Prozess inherits Eltern Konsole Fenster und IO-Handles. Wenn Sie die Shell schließen, indem Sie auf die x Schaltfläche klicken, erhält es daher CTRL_CLOSE_EVENT und verfügt nicht über eine Option, um nicht zu beenden.

Um dies zu vermeiden, sollte der untergeordnete Prozess nicht an die übergeordnete Konsole angefügt werden. Dies geschieht, indem Flag an CreateProcess Windows API übergeben wird.

standardmäßig eine Konsole Prozess erbt Konsole Mutter ... Console Prozesse sind nicht an eine Konsole angeschlossen, wenn sie unter Verwendung von Createprocess mit DETACHED_PROCESS erstellt werden.

From Creation of a Console MSDN docs.

Dies ist, was ich glaube Ruby spawn und win32-process Edelstein tun anders. Ich habe nicht versucht, beide zu debuggen, um den spezifischen Unterschied in den Flags zu sehen, die sie an CreateProcess liefern, obwohl das eine interessante Sache wäre, zu tun.

Es gibt andere Möglichkeiten, einen untergeordneten Prozess zu erstellen, ohne die Konsole oder IO-Handles des übergeordneten Elements zu erben. Beispiele sind CREATE_NO_WINDOW oder CREATE_NEW_CONSOLE Flags, Job Objects, usw.

+0

Wau, tolle Antwort und macht auch sehr viel Sinn. Der Win32-Prozess hat tatsächlich die Option Process :: DETACHED_PROCESS, die ich im aktualisierten Code verwende. Leider gibt es in Kernel.spawn keine anderen dokumentierten Flags abgesehen von dem Flag: new_pgroup, mit dem man die Erstellung des Prozesses steuern könnte. Klingt wie ein Fehler in der Ruby VM. Es muss entweder mehr Windows-spezifische Optionen verfügbar machen oder DETACHED_PROCESS standardmäßig festlegen. Man müsste den tatsächlichen Impl von Kernel.spawn überprüfen. Scheint Win32-Prozess ist die einzige Option für jetzt. – Hardy

+0

Nun, Ruby ist vor allem auf Unix-ähnlichen Plattformen beliebt. Da die Windows-Unterstützung keine Priorität und der große konzeptionelle Unterschied der Windows-API ist, würde ich sagen, 'spawn' verwendet einen ziemlich vernünftigen Ansatz, wenn es unter Windows aufgerufen wird. Schließlich ist ein eigenständiger, fensterloser Prozess in seinem Lebensraum verpönt, es sei denn, es handelt sich um einen Systemdienst. –

+0

Ich stimme zu Windows scheint ein Bürger zweiter Klasse zu sein. Ich stimme auch zu, dass in der Windows-Welt ein Systemdienst wahrscheinlich bevorzugt würde, aber das macht die Dinge noch schwieriger/divergenter, wenn Sie Code für alle Betriebssystemtypen schreiben wollen. In Bezug auf die Standardeinstellungen. Es scheint seltsam, bereits Windows-spezifische Flags anzubieten, aber nichts, um dieses Verhalten zu kontrollieren, und wenn nichts anderes mehr in der Dokumentation erwähnt werden sollte, sollte der Unterschied deutlicher sein. Wie auch immer, zumindest jetzt wissen wir :-) – Hardy

Verwandte Themen