2009-12-26 17 views
6

मैं एक पर्ल स्क्रिप्ट लिख रहा हूं जो कुछ इनपुट लिखेंगे और उन इनपुट को बाहरी कार्यक्रम में भेज देगा। वहाँ एक छोटी लेकिन गैर शून्य संभावना है कि इस कार्यक्रम रखती है, और मैं उसका समय हैं:मैं एक फोर्कड प्रक्रिया का समय कैसे लगा सकता हूं जो लटका सकता है?

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 के बाद, program_of_interest अभी भी बनी हुई है। मैं इस प्रकार $SIG{ALRM} के लिए अनाम सबरूटीन में यह मारने की कोशिश की:

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

लेकिन यह कुछ भी नहीं है। program_of_interest अभी भी जारी है। मैं इस प्रक्रिया को मारने के बारे में कैसे जा सकता हूं?

उत्तर

8

मैं द्वारा प्रक्रिया समूह को मारने के रूप में सफलतापूर्वक मेरी निष्पादन() ed प्रक्रिया को मारने में सक्षम था, जैसा कि In perl, killing child and its children when child was created using open प्रश्न के उत्तर के रूप में दिखाया गया है। मैंने अपना कोड निम्नानुसार संशोधित किया:

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

टाइमआउट के बाद, program_of_interest सफलतापूर्वक मारे गए।

+0

मुझे लगता है कि "मारो 9, - $ पीआईडी" "मार -9, $ पीआईडी" होना चाहिए। मैंने इसके बजाय सिस्टम ("मार -9 $ पीआईडी") का इस्तेमाल किया। – Boolean

+0

मुझे लगता है कि "kill -9 $ pID" को "kill -9 $ pid" होना चाहिए, लेकिन हां, नकारात्मक पिड केवल एक प्रक्रिया के बजाय एक प्रक्रिया समूह को मारने का संकेत देता है। हत्या दस्तावेज से: "शैल के विपरीत, यदि सिग्नल नकारात्मक है, तो यह प्रक्रियाओं के बजाय प्रक्रिया समूहों को मारता है। (सिस्टम वी पर, एक नकारात्मक प्रोसेस संख्या भी प्रक्रिया समूहों को मार डालेगी, लेकिन यह पोर्टेबल नहीं है।)" – simpleuser

2

हम्म आपके कोड मेरे लिए काम करता है, कुछ मामूली संशोधन के बाद - जो मुझे लगता है कि कोड को सामान्य उदाहरण में कोड बनाने के लिए आपके द्वारा किए गए परिवर्तन हैं।

तो है कि मुझे दो विचारों के साथ छोड़ देता है:

  1. जब आप नमूना कोड बनाई समस्या हटाया - एक छोटा सा नमूना है कि वास्तव में चलाता बनाने का प्रयास करें (मैं 'program_of_interest' और $ num_secs_to_timeout बदलना पड़ा परीक्षण करने के लिए वास्तविक मूल्यों के लिए)। सुनिश्चित करें कि नमूना एक ही समस्या है।
  2. यह प्रोग्राम_of_इन रुचि के साथ कुछ करना है जो आप चल रहे हैं - जहां तक ​​मुझे पता है, आप 9 को मारने के लिए मास्क नहीं कर सकते हैं, लेकिन शायद कुछ चल रहा है। क्या आपने वास्तव में सरल स्क्रिप्ट के साथ अपने कोड का परीक्षण करने का प्रयास किया है। मैंने अपने परीक्षण के लिए एक बनाया है जो (1) {प्रिंट "हाय \ n"; नींद 1; }
  3. कुछ और

गुड लक ...

+0

लगता है कि आप सही थे: प्रणाली ("गूंज blahblah | program_of_interest"): मैं वास्तव में program_of_interest में कुछ पहुंचाया। sh निष्पादित किया जा रहा था और ठीक से मारा गया था, लेकिन program_of_interest नहीं .. –

1

एक ही रास्ता SIGKILL अनदेखा किया जा सकता है, तो प्रक्रिया एक सिस्टम कॉल जो अबाधित है में फंस गया है है। यदि राज्य डी है, तो लटका प्रक्रिया की स्थिति (ps aux के साथ) की जांच करें, फिर प्रक्रिया को मार नहीं सकता है।

आप यह भी देखना चाहेंगे कि फ़ंक्शन को इससे कुछ आउटपुट करके बुलाया जा रहा है।

2

उपरोक्त कोड (सख्ती से 27) द्वारा बॉक्स से बाहर काम नहीं किया, क्योंकि - $ पीआईडी ​​राजधानियों में लिखा गया है। (BTW: वहाँ भी है: 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 
    } 
} 
संबंधित मुद्दे

 संबंधित मुद्दे