Frage

Ich schreibe ein Perl-Skript, das einige Eingaben schreiben wird und diese Eingänge an ein externes Programm senden. Es gibt eine kleine, aber nicht Null Chance, dass dieses Programm hängen, und ich mag es Zeit aus:

my $pid = fork;
if ($pid > 0){
    eval{
        local $SIG{ALRM} = sub { die "TIMEOUT!"};
        alarm $num_secs_to_timeout;
        waitpid($pid, 0);
        alarm 0;
    };
}
elsif ($pid == 0){
    exec('echo blahblah | program_of_interest');
    exit(0);
}

Wie es jetzt aussieht, nach $ num_secs_to_timeout, program_of_interest noch weiter besteht. Ich versuchte es in der anonymen Unterprogramm für $SIG{ALRM} zu töten, wie folgt:

local $SIG{ALRM} = sub{kill 9, $pid; die "TIMEOUT!"}

, aber das macht nichts. program_of_interest ist immer noch vorhanden. Wie gehe ich über diesen Prozess zu töten?

War es hilfreich?

Lösung

konnte ich erfolgreich meine exec () ed Prozess töten, indem sie Tötung der Prozessgruppe , wie die Antwort auf die Frage gezeigt in perl, Kind zu töten und seine Kinder, wenn Kind erstellt wurde geöffnet . Ich änderte meinen Code wie folgt:

my $pid = fork;
if ($pid > 0){
    eval{
        local $SIG{ALRM} = sub {kill 9, -$PID; die "TIMEOUT!"};
        alarm $num_secs_to_timeout;
        waitpid($pid, 0);
        alarm 0;
    };
}
elsif ($pid == 0){
    setpgrp(0,0);
    exec('echo blahblah | program_of_interest');
    exit(0);
}

Nach Ablauf dieser Zeit wird program_of_interest erfolgreich getötet.

Andere Tipps

Der obige Code (von strictlyrude27) funktionierte nicht aus der Box, weil - $ PID in Großbuchstaben geschrieben ist. (BTW: Es gibt auch: http://www.gnu.org /software/coreutils/manual/html_node/timeout-invocation.html )

Hier ist ein Beispiel mit Test:

#!/usr/bin/perl
use strict;
use warnings;
use File::Basename;

my $prg = basename $0;
my $num_secs_sleep = 2;
my $num_secs_to_timeout = 1;
my $orig_program = "sleep $num_secs_sleep; echo \"Look ma, survived!\"";
my $program = $orig_program;
my $expect = "";

if (@ARGV){
  if($ARGV[0] eq "test"){
    test();
    exit 0;
  } elsif (@ARGV == 1) {
    $num_secs_to_timeout = $ARGV[0];
  } elsif (@ARGV == 2) {
    $program = $ARGV[0];
    $num_secs_to_timeout = $ARGV[1];
  } else {
    die "Usage: $prg [ \"test\" | [program] seconds ] "
  }
}

if($orig_program eq $program) {
  if(@ARGV < 2) {
    $expect = $num_secs_to_timeout > $num_secs_sleep ?
      "(we expected to survive.)" : "(we expected to TIME OUT!)";
  }
  print STDERR "sleeping: $num_secs_sleep seconds$/";
}

print STDERR <<END;
  timeout after: $num_secs_to_timeout seconds,
  running program: '$program'
END

if($orig_program eq $program) {
  print STDERR "$expect$/";
}

exit Timed::timed($program, $num_secs_to_timeout);

sub test {
  eval "use Test::More qw(no_plan);";
  my $stdout;
  close STDOUT;
  open STDOUT, '>', \$stdout or die "Can't open STDOUT: $!";
  Timed::timed("sleep 1", 3);
  is($stdout, undef);
  Timed::timed("sleep 2", 1);
  is($stdout, "TIME OUT!$/");
}

################################################################################
package Timed;
use strict;
use warnings;

sub timed {
  my $retval;
  my ($program, $num_secs_to_timeout) = @_;
  my $pid = fork;
  if ($pid > 0){ # parent process
    eval{
      local $SIG{ALRM} = 
        sub {kill 9, -$pid; print STDOUT "TIME OUT!$/"; $retval = 124;};
      alarm $num_secs_to_timeout;
      waitpid($pid, 0);
      alarm 0;
    };
    return defined($retval) ? $retval : $?>>8;
  }
  elsif ($pid == 0){ # child process
    setpgrp(0,0);
    exec($program);
  } else { # forking not successful
  }
}

Hmmm Ihr Code funktioniert bei mir , nachdem einige kleinere Änderungen -., Die ich davon ausgehen, sind Änderungen von sich aus, um den Code in ein allgemeines Beispiel zu machen

Damit läßt mich mit zwei Ideen:

  1. Sie entfernt das Problem, wenn Sie den Beispielcode erstellt - versuchen, eine kleine Probe zu schaffen, dass tatsächlich läuft (ich ändern ‚program_of_interest‘ hatte und $ num_secs_to_timeout auf reale Werte, die es zu testen). Achten Sie darauf, die Probe hat das gleiche Problem.
  2. Es ist etwas mit dem program_of_interest zu tun Sie laufen - soweit ich weiß, kann man nicht eine Abtötung 9, Maske, aber vielleicht gibt es etwas los. Haben Sie versuchen, Ihren Code mit einem wirklich einfachen Skript zu testen. Ich habe für meine Tests, die während geht (1) {print „hallo \ n“; sleep 1; }
  3. Etwas anderes .

Viel Glück ...

Der einzige Weg, SIGKILL ignoriert werden kann, wenn das Verfahren in einem Systemaufruf stecken, die unterbrechungsfrei ist. Überprüfen Sie den Zustand des aufgehängten Prozess (mit ps aux), wenn der Zustand D ist, dann kann der Prozess nicht getötet werden.

Sie mögen vielleicht auch prüfen, ob die Funktion durch die Ausgabe etwas von ihm aufgerufen wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top