Question

Je suis en train d'écrire un script Perl qui va écrire des entrées et envoyer ces entrées à un programme externe. Il y a une chance petite mais non nulle que ce programme se bloque, et je veux en temps dehors:

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);
}

À l'heure actuelle, après num_secs_to_timeout de $, program_of_interest persiste encore. J'ai essayé de le tuer dans le sous-programme anonyme pour $SIG{ALRM} comme suit:

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

mais cela ne fait rien. program_of_interest est toujours persistant. Comment puis-je de tuer ce processus?

Était-ce utile?

La solution

J'ai pu tuer avec succès mon processus ed exec () par tuer le groupe de processus , comme indiqué que la réponse à la question en perl, tuant l'enfant et ses enfants lorsque l'enfant a été créé à l'aide ouvert . Je modifié mon code comme suit:

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);
}

Au terme du délai, program_of_interest est tué avec succès.

Autres conseils

Le code ci-dessus (par strictlyrude27) ne fonctionne pas hors de la boîte, parce que - $ PID est écrit en majuscules. (BTW: il y a aussi: http://www.gnu.org /software/coreutils/manual/html_node/timeout-invocation.html)

Voici un exemple avec le 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 votre code fonctionne pour moi , après quelques modifications mineures -. Que je suppose sont les changements apportés par vous-même pour faire le code dans un exemple générique

Alors, qui me laisse avec deux idées:

  1. Vous avez supprimé le problème lorsque vous avez créé l'exemple de code - essayez de créer un petit échantillon qui fonctionne réellement (je devais changer « program_of_interest » et num_secs_to_timeout $ à des valeurs réelles pour le tester). Assurez-vous que l'échantillon a le même problème.
  2. Il est quelque chose à voir avec le program_of_interest que vous utilisez - pour autant que je sache, vous ne pouvez pas masquer un kill 9, mais peut-être il y a quelque chose. Avez-vous essayé de tester votre code avec un script très simple. J'ai créé un pour mes tests qui va while (1) {print « salut \ n »; sommeil 1; }
  3. Quelque chose d'autre .

Bonne chance ...

La seule façon SIGKILL peut être ignoré est si le processus est bloqué dans un appel système qui est sans coupure. Vérifier l'état du processus hung (avec ps aux) si l'état est D, le processus ne peut pas être tué.

Vous pouvez également vérifier que la fonction est appelée en sortant quelque chose.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top