2009-12-26 25 views
6

Tôi đang viết một kịch bản Perl sẽ viết một số đầu vào và gửi các đầu vào đó đến một chương trình bên ngoài. Có một nhỏ nhưng khác không cơ hội mà chương trình này sẽ treo, và tôi muốn để thời gian nó ra:Làm thế nào tôi có thể hết thời gian chờ một quá trình chia đôi có thể treo?

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

Khi đứng bây giờ, sau khi $ num_secs_to_timeout, program_of_interest vẫn còn dai dẳng. Tôi đã cố gắng xóa nó trong chương trình con ẩn danh cho $SIG{ALRM} như sau:

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

nhưng điều này không làm gì cả. program_of_interest vẫn còn tồn tại. Làm thế nào để tôi đi về việc giết chết quá trình này?

Trả lời

8

Tôi đã có thể giết thành công quy trình thực thi() của mình bằng cách giết nhóm quá trình, như được hiển thị là câu trả lời cho câu hỏi In perl, killing child and its children when child was created using open. Tôi đã sửa đổi mã của mình như sau:

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

Sau khi hết giờ, chương trình_of_interest bị giết thành công.

+0

Tôi nghĩ rằng "giết 9, - $ PID" nên được "giết -9, $ PID". Tôi đã sử dụng hệ thống ("kill -9 $ PID"). – Boolean

+0

Tôi nghĩ rằng "giết -9 $ PID" nên tiếp tục là "giết -9 $ pid", nhưng có, pid tiêu cực chỉ ra để giết một nhóm quá trình thay vì chỉ là một quá trình. Từ tài liệu giết: "Không giống như trong shell, nếu SIGNAL là tiêu cực, nó sẽ giết chết các nhóm tiến trình thay vì các tiến trình. (Trên hệ thống V, một số PROCESS âm cũng sẽ giết các nhóm tiến trình, nhưng đó không phải là di động.)" – simpleuser

2

Hmmm mã của bạn hoạt động cho tôi, sau một số sửa đổi nhỏ - mà tôi giả định là những thay đổi được thực hiện bởi chính bạn để biến mã thành ví dụ chung.

Vì vậy mà lá tôi với hai ý tưởng:

  1. Bạn đã xóa vấn đề khi bạn tạo ra các mẫu mã - hãy thử tạo một mẫu nhỏ mà thực sự chạy (tôi đã phải thay đổi 'program_of_interest' và $ num_secs_to_timeout với giá trị thực để kiểm tra nó). Đảm bảo mẫu có cùng vấn đề.
  2. Đó là điều cần làm với chương trình_of_interest bạn đang chạy - theo như tôi biết, bạn không thể che dấu một kill 9, nhưng có thể có điều gì đó đang diễn ra. Bạn đã thử kiểm tra mã của mình bằng một tập lệnh thực sự đơn giản chưa. Tôi đã tạo một bản để thử nghiệm trong khi (1) {in "hi \ n"; ngủ 1; }
  3. Cái gì khác.

Chúc may mắn ...

+0

Hình như bạn đã đúng: Tôi thực sự cấp nước tập trung cái gì đó vào program_of_interest: hệ thống ("echo blahblah | program_of_interest"). sh đã được exec'd và đúng cách giết chết, nhưng không program_of_interest .. –

1

Cách duy nhất SIGKILL thể bỏ qua là nếu quá trình này bị mắc kẹt trong một cuộc gọi hệ thống đó là liên tục. Kiểm tra trạng thái của quá trình treo (với ps aux) nếu trạng thái là D, thì quá trình này không thể bị giết.

Bạn cũng có thể muốn kiểm tra xem hàm có đang được gọi hay không bằng cách xuất một thứ gì đó từ nó.

2

Đoạn mã trên (do strictrude27) không hoạt động, vì - $ PID được viết bằng chữ in hoa. (BTW: có thêm: http://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html)

Dưới đây là một ví dụ với bài kiểm tra:

#!/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 
    } 
} 
Các vấn đề liên quan