2016-05-17 68 views
1

我正在使用一個Perl腳本,它使用 waitpid($pid, 0)等待當前進程完成。 但是print在此之後編寫的陳述waitpid在過程完成之前正在打印它。如何在運行進程不是子進程時等待運行進程在perl中完成?

我想知道爲什麼waitpid不是先等待流程完成。

此外,運行過程的控制是在不同的模塊下,而不是這個perl腳本的一部分。只能訪問進程的pid和名稱。我無法更改調用該過程的模塊中的任何內容。

+0

您確定'$ pid'是您認爲的嗎? 'waitpid'的返回值是什麼?它將指示什麼進程終止。 – Schwern

+0

@Schwern - waitpid的返回值是-1。這意味着我沒有這樣的孩子過程。我添加下面的行來檢查$ pid是否正在運行。我的$ exists = kill 0,$ pid; ($存在);打印「進程正在運行\ n」( );並且它會打印語句 – user3395103

+2

您不能。您只能在子進程上「等待」。請參閱'perldoc wait'(或'waitpid',這是一樣的),第一句。如果你想知道外部程序何時完成,你必須做完全不同的事情。 – zdim

回答

2

備註   kill 0, $pid最後一個簡單的單線發表評論。


我們需要檢測一個外部程序的完成,這個腳本還沒有啓動。該問題詢問使用waitpid。複製我的早評:

你不能。您只能等待子進程。見perldoc wait(或waitpid,這是一樣的),第一句話。

waitwaitpid等待傳遞給腳本的關於其子(命令)的命運的信號。腳本沒有理由接收有關它沒有啓動的進程的信號。


我們知道進程的id和它的名字。它的PID可用於查詢是否正在運行。使用pid本身並不完全可靠,因爲在我們的檢查之間,該過程可以結束,並且隨機分配一個新的pid。我們可以使用該程序的名稱來加強這一點。

在Linux系統上,有關進程的信息可以通過使用(許多ps選項獲得。這兩種收益的程序的完整調用

 
ps --no-headers -o cmd PID 
ps --no-headers -p PID -o cmd 

返回的字符串可能與解釋程序的路徑開始(一個Perl腳本,例如),其次是程序的全名。版本ps -p PID -o comm=只返回程序的名稱,但我發現它可能會打破連字符(如果有),導致名稱不完整。這可能需要在某些系統上調整,請諮詢您的man ps。如果沒有給定PID的過程,我們什麼也得不到。

然後我們可以檢查PID,如果找到,檢查該PID的名稱是否與程序匹配。該程序的名稱是已知的,我們可以硬編碼。但是,腳本在啓動時仍使用上述ps命令來獲取,以避免含糊不清。 (然後它也採用相同的格式用於以後的比較。)由於不能保證腳本執行時的PID確實用於預期的程序,因此會根據已知名稱檢查它本身。

use warnings; 
use strict; 

# For testing. Retrieve your PID as appropriate for real use  
my $ext_pid = $ARGV[0] || $$; 

my $cmd_get_name = "ps --no-headers -o cmd $ext_pid"; 

# For testing. Replace 'sleep' by your program name for real use 
my $known_prog_name = 'sleep'; 

# Get the name of the program with PID 
my $prog_name = qx($cmd_get_name); 

# Test against the known name, exit if there is a mismatch 
if ($prog_name !~ $known_prog_name) { 
    warn "Mismatch between:\n$prog_name\n$known_prog_name -- $!"; 
    exit; 
} 

my $name; 
while ($name = qx($cmd_get_name) and $name =~ /$prog_name/) 
{ 
    print "Sleeping 1 sec ... \n"; 
    sleep 1; 
} 
# regex above may need slight adjustment, depending on format of ps return 

經由qx()接收到的命令輸出上述(反引號運算符)含有換行符。如果這證明是腳本中的問題,那麼它可以是chomp -ed,這需要稍微調整。其餘的漏洞是很程序可能已經完成並且在檢查之間重新啓動,並且具有相同的PID。

這將通過在殼

 
sleep 30 & 
script.pl `ps aux | egrep '[s]leep'` 

egrepgrep -E運行進行測試。 `ps ...`的輸出包含多個單詞。這些作爲命令行參數傳遞給我們的腳本,該腳本使用第一個作爲PID。如果出現問題,請先運行ps篩選,然後手動輸入PID作爲腳本的輸入參數。上面30秒的sleep是給予足夠的時間在命令行上完成所有這些。

如果程序名稱足夠獨特且不會更改,則可以通過將$name與硬編碼的$prog_name進行匹配來簡化代碼。 上面使用的硬編碼名稱,但是對於檢查,如果不匹配,它會生成警告。如果這個過程是由相同的用戶腳本可以使用kill 0, $pid資(如果我們依靠它只能硬編碼,我們不能發出警告,如果不匹配,因爲這是隨後的代碼的操作的一部分。)


作爲

while (kill 0, $ext_pid) { sleep 1 } 

然後,你要麼必須撥打另一個電話,以檢查名稱或滿足於在什麼實際過程中$pid表示錯誤的(小)的可能性。

模塊Proc::ProcessTable可以用於所有這些。在Windows系統上,這將是一條路。

+0

是的,它爲我工作 – user3395103

+0

@ user3395103很高興工作。結果是一個很長的帖子,讓我知道是否有任何問題或問題。 – zdim

3

waitpid documentation狀態:

等待特定子進程終止,並返回死者進程的PID ,或-1,如果沒有這樣的子進程。

快速測試:

my $pid = open my $fh,"-|","sleep 3"; 
print waitpid(28779,0); # Some other process 
print waitpid($pid,0); 

28779是目前運行的另一個進程(從拿了一個ps axu隨機一個)。輸出:

-1 
4088 

不能使用waitpid等待的過程,是不是你的當前進程的孩子。

The kill command可以檢查是否一個PID正在運行:

print kill(0,28779); 

輸出:

1 

你還是會需要輪詢(睡眠循環)爲PID消失。另外請記住,受監視的進程可能會退出,並且在下次檢查之前新的可能會重複使用相同的PID(不太可能,但可能)。