2013-02-21 35 views
4

我正在Linux主機上運行perl腳本。我試圖寫一個腳本,分叉,孩子開始一個永久需要的程序,父母在5秒後超時,殺死孩子。以下是我有:

my $start = time(); 
my $timeOut = 5; 

my $childPid = fork(); 
if ($childPid) { 
    # I am the parent, and $childPid is my child 
    while (kill(0, $childPid)) { 
     if (time() > $start + $timeOut) { 
      $numKilled = kill(SIGTERM, $childPid); 
      printf("numKilled: %s\n", $numKilled); 
     } 
     sleep 1; 
    } 
} 
else { 
    # I am the child - do something that blocks forever 
    `adb -s 410bf6c1 logcat`; 
    exit; 
} 

輸出:

[email protected]:~$ perl perl-fork-test.pl 
numKilled: 1 
numKilled: 1 
numKilled: 1 
numKilled: 1 
numKilled: 1 
... 

我期望的行爲,我看到「numKilled:1」恰好一次,和子進程(及其任何子女)爲大約5秒後死亡。但是我從實驗中看到,孩子和孩子都沒有死亡。 kill(SIGTERM, $childPid)似乎什麼都不做。

我怎麼能真正殺死孩子?

+1

你是從某處導入SIGTERM常量嗎?我敢打賭,它的評估結果爲0. – friedo 2013-02-21 21:11:47

+1

您是否在使用'use warnings;嚴格使用;'?爲什麼不? – melpomene 2013-02-21 21:27:49

+0

嘿傢伙們,所以我發現我看到的問題實際上有些不同 - 殺死孩子的過程而不是孩子的任何過程。我不想只編輯整個問題,我應該開始一個新問題嗎? – 2013-02-21 22:40:33

回答

3

perldoc fork

如果沒有叉子上你的孩子永遠在等待,你會積累 殭屍。在某些系統上,您可以通過將$ SIG {CHLD}設置爲 「IGNORE」來避免此情況。

$SIG{CHLD} = 'IGNORE';添加到代碼的頂部時,我能夠獲得所需的行爲。

[[email protected] ~]$ perl test.pl 
numKilled: 1 
[[email protected] ~]$ 

另外,加入waitpid($childPid, 0);kill的伎倆後爲好。

1

有機會,你是use ING既不在你的腳本strict也不POSIX,所以SIGTERM被解釋爲裸字"SIGTERM",這是不是一個有用的行爲方式。

use strict使這個偶然的裸詞變成了一個錯誤,然後use POSIX拉到SIGTERM常量。

+0

或者只是'殺死'TERM',$ pid'並且不用打擾常量。 – melpomene 2013-02-21 21:29:28

+0

請參閱http://perldoc.perl.org/functions/kill.html:「您也可以在引號中使用信號名稱。」 – melpomene 2013-02-21 21:39:49

+0

啊,它是!錯過了我第一次閱讀。 – duskwuff 2013-02-21 21:41:43

1

我也看到這種行爲,即使在流程結束後,kill 0也會返回true;我懷疑你可能錯過了waitpid的調用(通常在SIGCHLD處理程序中完成),這會導致這種情況,但即使在添加它之後,kill 0仍會繼續返回true。

我建議你使用非阻塞的waitpid而不是kill(並且驗證該進程實際上是否在SIGTERM信號上死亡 - 有些可能不會,至少是立即)。如果SIGTERM不起作用,並且在最後的SIGKILL中,您可能還想在一段時間後嘗試SIGINT。

5

應該是這樣的。這是不遵循最佳實踐,但它應該幫助你解決問題...

#!/usr/bin/perl 

use warnings; 
use strict; 
use POSIX qw(:sys_wait_h); 

my $timeOut = 5; 
$SIG{ALRM} = \&timeout; 
$SIG{CHLD} = 'IGNORE', 
alarm($timeOut); 

my $childPid = fork(); 
if ($childPid) { 
    while(1) { 
     print "[$$]: parent...\n"; 
     sleep(2); 
    } 
}else { 
    # I am the child - do something that blocks forever 
    while(1){ 
     print "[$$]: child...\n"; 
     sleep(2); 
    } 
    exit; 
} 

sub timeout { 
    print "killing $childPid\n"; 
    print "###\n" . `ps -ef | grep -v grep | grep perl` . "###\n"; 
    if (! (waitpid($childPid, WNOHANG))) { 
     print "killing $childPid...\n"; 
     kill 9, $childPid; 
     die "[$$]: exiting\n"; 
    } 
} 

OUTPUT:

$ forktest.pl 
[24118]: parent... 
[24119]: child... 
[24118]: parent... 
[24119]: child... 
[24118]: parent... 
[24119]: child... 
killing 24119 
### 
cblack 24118 12548 0 14:12 pts/8 00:00:00 /usr/bin/perl ./forktest.pl 
cblack 24119 24118 0 14:12 pts/8 00:00:00 /usr/bin/perl ./forktest.pl 
### 
killing 24119... 
[24118]: exiting 
1

嘗試殺死進程組(使用 - $ PID):

kill TERM => -$pid; 

參見perlipc。

0

我認爲問題與'0'你作爲'殺死'的第一個參數傳遞。當我閱讀文檔時,他們說'0'只會檢查是否可以發送信號給進程,而不發送它。在你的情況下,你想發送'KILL'信號給子進程,所以這樣做:

kill('KILL', $childPid); 
+1

kill(0,$ childPid)基本上是說如果進程正在運行,然後繼續..隨後他發送一個SIGTERM – Hariboo 2017-07-26 12:40:39

相關問題