2010-03-21 6 views
5

Tôi đang chạy một Bot IRC (Bot::BasicBot) có hai quy trình con chạy File::Tail nhưng khi thoát, chúng không chấm dứt. Vì vậy, tôi killling chúng bằng cách sử Proc::ProcessTable như thế này trước khi thoát:Cách nào đúng để giết các tiến trình con trong perl trước khi thoát?

my $parent=$$; 
my $proc_table=Proc::ProcessTable->new(); 
for my $proc (@{$proc_table->table()}) { 
    kill(15, $proc->pid) if ($proc->ppid == $parent); 
} 

Nó hoạt động nhưng tôi nhận được cảnh báo này:

 
14045: !!! Child process PID:14047 reaped: 
14045: !!! Child process PID:14048 reaped: 
14045: !!! Your program may not be using sig_child() to reap processes. 
14045: !!! In extreme cases, your program can force a system reboot 
14045: !!! if this resource leakage is not corrected. 

tôi có thể làm gì khác để giết tiến trình con? Quá trình chia đôi được tạo bằng phương thức forkit trong Bot::BasicBot.

Mẫu kịch bản:

package main; 

my $bot = SOMEBOT->new (server => 'irc.dal.net', channels => ['#anemptychannel']); 

$SIG{'INT'} = 'Handler'; 
$SIG{'TERM'} = 'Handler'; 

sub Handler { 
$bot->_stop('Leaving.'); 
} 

$bot->run; 

package SOMEBOT; 

use base qw(Bot::BasicBot); 
use File::Tail; 
use Proc::ProcessTable; 
sub irc_error_state { die if $_[10] =~ /Leaving\./; } 
sub help { return; } 


sub stop_state { 
my $parent=$$; 
my $proc_table=Proc::ProcessTable->new(); 
for my $proc (@{$proc_table->table()}) { 
    kill(15, $proc->pid) if ($proc->ppid == $parent); 
} 
die; 

} 

sub connected { 
my $self = shift; 

$self->forkit (
       run  => \&announcer, 
       body => '/home/somebody/somefile.txt', 
       channel => '#anemptychannel', 
      ) unless $self->{log1}; 
$self->{log1} = 1; 


$self->forkit (
       run  => \&announcer, 
       body => '/home/somebody/anotherfile.txt', 
       channel => '#anemptychannel', 
      ) unless $self->{log2}; 
$self->{log2} = 1; 

} 

sub announcer { 
my $announcefile = shift; 
my $file=File::Tail->new(name => $announcefile, maxinterval=>5, adjustafter=>7); 
while (defined(my $line=$file->read)) { chomp $line; print "$line\n"; } 
} 
+2

Xin chào, không có vấn đề gì với cách bạn đang giết các tiến trình con. Cảnh báo chỉ nói rằng bạn chưa đăng ký một cuộc gọi lại POE khi các quá trình này chết - bạn cần phải đăng ký chúng với POE-> kernel-> sig_child(). Xem: http://kobesearch.cpan.org/htdocs/POE/POE/Kernel.html#sig_child_PROCESS_ID_EVENT_NAME – Martin

Trả lời

0

Tôi muốn được quan tâm tại sao tiến trình con của bạn không kết thúc đúng cách. Trong hoàn cảnh "bình thường", phụ huynh không cần phải làm bất cứ điều gì (có thể gọi waitpid nếu bạn quan tâm đến kết quả, hoặc ngừng xử lý cho đến khi chúng được thực hiện).

Điều này chưa thực sự là câu trả lời - có thể bạn sẽ phải dán một số mã ở trẻ em. Nhưng một chút lời khuyên - bắt đầu với các chương trình đơn giản gọi là fork theo cách thủ công, thay vì dựa vào mô-đun CPAN để làm điều đó cho bạn. Điều quan trọng là phải hiểu cách nhiều hệ thống được xử lý bởi hệ thống. Sau đó, khi bạn đã có, bạn có thể tận dụng một số khuôn khổ để xử lý rất nhiều quy trình cho bạn.

Bạn cũng có thể đọc qua perldoc perlfork nếu gần đây bạn chưa thực hiện và thử một số ví dụ.

+0

Có lẽ vì tôi không chấm dứt bot đúng cách. Tôi hỏi một câu hỏi về điều đó vài ngày trước. http://stackoverflow.com/questions/2471373/how-do-i-correctly-shutdown-a-botbasicbot-bot-based-on-poecomponentirc – rarbox

1

Tôi không quen thuộc với bất kỳ các module bạn đề cập đến, nhưng khi tôi đã viết forking chương trình Perl trong quá khứ đó, nó đã thường đủ để đưa dòng này trong quá trình cha mẹ chính:

$SIG{CHLD} = sub { wait }; 

Bằng cách đó, khi một quá trình con thoát ra và quá trình cha mẹ nhận được một tín hiệu SIGCHLD, nó sẽ tự động gặt hái con với wait.

+0

Đã thử điều đó và không hoạt động. Tôi nhấn Ctrl + C lần đầu tiên và nó không làm gì cả. Tôi đã làm nó một lần nữa và nó chấm dứt mà không giết chết các tiến trình con. Quá trình con được cho là chạy vô thời hạn (giống như chạy "đuôi -F") trừ khi bị giết. Nó sẽ không tự chấm dứt. – rarbox

1

Kể từ phiên bản 0.82, Bot::BasicBot sẽ giết các quy trình con xuất sắc (được tạo bởi forkit()) khi thoát.

1

Tôi đang đào lên một bài đăng cũ, nhưng tôi đang tìm kiếm câu trả lời cho câu hỏi này và tìm kiếm của Google đặt câu trả lời này là kết quả hàng đầu. Vì vậy, trong trường hợp bất cứ ai khác tình cờ về điều này, đây là cách tôi đã làm nó.

Trước khi forking, thiết lập một pipe quá trình chia hai bạn có thể giao tiếp:

pipe PARENTRECEIVE,CHILDSEND;

Fork quá trình của bạn và có con gửi cha mẹ quá trình ID mới immendiately. Sau đó, khi bạn nghĩ rằng con là treo (hoặc thông qua một bộ đếm thời gian hoặc một SIG), bạn có thể giết chết quá trình con:

my $pid = fork(); 
if ($pid eq 0) { 
    #child block 
    my $cid = $$;  
    print CHILDSEND "$cid\n"; 
    <do child stuff which might hang> 
} 
else { 
    #parent block 
    my $child_id = <PARENTRECEIVE>; 
    chomp $child_id; 
    <do parent stuff> 
    <if you think child is hung> { 
    kill 1, $child_id; 
    } 
} 

Đôi khi treo máy chủ web của chúng tôi, vì vậy tôi sử dụng để kiểm tra xem nếu nó vẫn đáp ứng Yêu cầu HTTP GET trong một khoảng thời gian hợp lý. Nếu đứa trẻ không hoàn thành việc lấy URL trước khi bộ đếm thời gian của người phụ huynh bật lên, nó sẽ gửi một cảnh báo qua email để nói điều gì đó đang hoạt động.