2013-11-25 12 views
5

Ich bin in Windows einen Perl-Skript ausgeführt wird, der eine ausführbare Datei aufruft:Perl Kommandozeileninterpreter Verlassen nicht

$command = "$path_to_exe -i $dir -o $results"; 
my $pid = fork(); 

    if (!$pid) { 
     system($command); 

     #do stuff 

    } else { 
     #do stuff 
    } 

print "Exiting..." 
exit; 

Statt nach dem Austritt aus perl.exe leerläuft gerade. Ein Popup-Fenster sagt mir, dass der Perl-Befehlszeilen-Interpreter nicht mehr funktioniert.

Ich weiß nicht viel über Prozess-Management in Windows, und ich habe zuvor in diesem Forum gelesen, dass es keine gute Praxis ist, fork() und exec() zu verwenden, aber der Code funktioniert gut neben dem Interpreter nicht Teil zu schließen. Ich habe alles ausprobiert, um das Programm in Unix zu implementieren (das den gleichen Fehler gibt), um Win32::Process Befehle zu verwenden - aber nichts funktioniert. Ich hoffte, dass es eine einfachere Lösung geben würde, die es mir ermöglichen würde, das zu bewahren, was ich bereits geschrieben habe.

Wenn jemand erklären könnte, was genau in Windows passiert, wenn dieser Code ausgeführt wird, wäre das auch eine Hilfe!

+0

gabel exec ist keine gute Praxis auf Sieg, weil Sieg nicht darauf optimiert ist. Win ist zu massiven Threading und lokalen RPC optimiert. Aber in Ihrem Fall ist es kein echtes Problem, denn für Sie ist es nicht wirklich wichtig, dass Ihr Wrapper-Skript 0,001s oder 0,01s Overhead produziert. Es war nur wichtig, wenn Sie zum Beispiel einen Datenbankserver-Daemon oder etwas hatten, das tausendmal pro Sekunde aufgerufen werden muss. Eine andere Sache, dass ja, fork() - exec() ist langsam, aber fork() - system() ist sogar so langsam ... Ich sehe weiter, dass Sie einfach nicht auf mein zweites Problem ($ pid und nicht $$). Du solltest kooperativ sein. – peterh

Antwort

4

Ich kann 2 unabhängige Probleme sehen.

  1. system() schafft ein Kind-Prozess, so dass, wenn Sie ein system() aus einem gegabelten Kind nennen, werden Sie 3-Prozesse haben. Aber Sie töten nur die Sekunde (das gegabelte Kind) und das Kind des Kindes (das $ -Kommando) nicht. Versuchen Sie, eine Funktion wie exec() zu verwenden, auf Unix startet es den Kindprozess auf dem Platz (und auf der PID) des tatsächlichen Prozesses. Wenn Sie Glück haben, macht Perl unter Windows dasselbe.

  2. im übergeordneten Thread Sie $$ töten, die den aktuellen Prozess ist. Wahrscheinlich wollten Sie $pid (das ist die PID des untergeordneten Prozesses im übergeordneten Thread) töten.

+0

Ich experimentierte mit exec(), und ich fand, dass es auch nicht beendet. Ich werde es erneut versuchen und sehen, was passiert.'$ pid' in Windows ist nicht das' $ pid' des Kindprozesses, es ist eine negative Zahl, die, glaube ich, einem Pseudoprozess entspricht. Irgendwie ist die Art, wie ich 'taskkill' benutzt habe, funktional, frag mich nicht wie. Danke – user86895

+0

Ich denke dein Weg zum Überleben ist, wenn du blindes Schießen einstellst und beginnst, mit deinen Händen und Augen zu zielen. – peterh

1

ich verwendet, um die folgenden (es mal aus dem Programm und, was am wichtigsten ist, brechen nicht den Perl-Interpreter!):

use Win32::Job; 
my $job = Win32::Job->new; 

    # Run $command for $max_time 
    $job->spawn($Config{"path/cmd.exe"}, $command); 
    $job->run($max_time); 
    exit; 
1

In meinem Fall habe ich entfernt, einige „Verwendung“ Aussagen und es wurde gelöst. Es passiert wahrscheinlich, weil die Perl-Implementierung für "fork" unter Windows nicht perfekt ist und Probleme beim Importieren einiger "schwerer" Objekte wie der OLE-Bibliothek hat.

Der genaue Einsatz mich entfernt:

#use Win32::OLE qw(in with); 
#use Win32::OLE::Const 'Microsoft Excel'; 

Umgehung: Wenn möglich, versucht Import dynamisch die Bibliotheken nach dem Punkt gibt es keine Gabel in dem Code.

Beispiel für meinen Fall:

# code with fork 
eval "use Win32::OLE::Const 'Microsoft Excel';"; 
eval "use Win32::OLE qw(in with);"; 
# code without fork