كيف يمكنني مهلة عملية متشعب قد تكون معلقة؟

StackOverflow https://stackoverflow.com/questions/1962985

  •  21-09-2019
  •  | 
  •  

سؤال

أنا أكتب برنامج نصي Perl الذي يكتب بعض المدخلات وإرسال هذه المدخلات إلى برنامج خارجي. هناك فرصة صغيرة ولكن غير صفرية سيتم تعليق هذا البرنامج ، وأريد أن أخرجه:

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

كما هو الحال الآن ، بعد $ num_secs_to_timeout ، لا يزال برنامج _of_interest مستمر. حاولت قتله في روتين فرعي مجهول $SIG{ALRM} على النحو التالي:

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

لكن هذا لا يفعل أي شيء. لا يزال برنامج program_of_interest مستمرًا. كيف يمكنني قتل هذه العملية؟

هل كانت مفيدة؟

المحلول

تمكنت من قتل عملية exec () بنجاح قتل مجموعة العملية, ، كما هو موضح كإجابة على السؤال في بيرل ، قتل الطفل وأطفاله عندما تم إنشاء الطفل باستخدام مفتوح. لقد قمت بتعديل الكود الخاص بي على النحو التالي:

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

بعد مهلة ، يتم قتل برنامج_البرمست.

نصائح أخرى

لم ينجح الرمز أعلاه (بواسطة StrictlyRude27) خارج الصندوق ، لأنه -يتم توضيح -$ pid في العواصم. (راجع للشغل: هناك أيضا: http://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html)

إليك مثال مع الاختبار:

#!/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
  }
}

أمم الرمز الخاص بك يعمل من أجلي, ، بعد بعض التعديلات البسيطة - التي أفترض أنها تغييرات أجراها بنفسك لجعل الكود في مثال عام.

لذلك يتركني مع فكرتين:

  1. قمت بإزالة المشكلة عند إنشاء رمز العينة - حاول إنشاء عينة صغيرة تعمل بالفعل (اضطررت إلى تغيير "program_of_interest" و $ num_secs_to_timeout إلى قيم حقيقية لاختبارها). تأكد من أن العينة لديها نفس المشكلة.
  2. إنه شيء يتعلق بـ program_of_interest الذي تقوم بتشغيله - على حد علمي ، لا يمكنك إخفاء القتل 9 ، ولكن ربما يكون هناك شيء ما يحدث. هل حاولت اختبار الكود الخاص بك باستخدام نص بسيط حقًا. لقد قمت بإنشاء واحد للاختبار الذي يذهب بينما (1) {print "hi n" ؛ النوم 1 ؛ }
  3. شيء آخر.

حظا طيبا وفقك الله...

الطريقة الوحيدة التي يمكن تجاهلها Sigkill هي ما إذا كانت العملية عالقة في مكالمة النظام غير متوقعة. تحقق من حالة عملية Hung (مع ps aux) إذا كانت الدولة د ، فلا يمكن قتل العملية.

قد ترغب أيضًا في التحقق من أن الوظيفة يتم استدعاؤها عن طريق إخراج شيء منه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top