我正在使用一個Perl腳本,它使用 waitpid($pid, 0)
等待當前進程完成。 但是print
在此之後編寫的陳述waitpid
在過程完成之前正在打印它。如何在運行進程不是子進程時等待運行進程在perl中完成?
我想知道爲什麼waitpid
不是先等待流程完成。
此外,運行過程的控制是在不同的模塊下,而不是這個perl腳本的一部分。只能訪問進程的pid和名稱。我無法更改調用該過程的模塊中的任何內容。
我正在使用一個Perl腳本,它使用 waitpid($pid, 0)
等待當前進程完成。 但是print
在此之後編寫的陳述waitpid
在過程完成之前正在打印它。如何在運行進程不是子進程時等待運行進程在perl中完成?
我想知道爲什麼waitpid
不是先等待流程完成。
此外,運行過程的控制是在不同的模塊下,而不是這個perl腳本的一部分。只能訪問進程的pid和名稱。我無法更改調用該過程的模塊中的任何內容。
備註 kill 0, $pid
最後一個簡單的單線發表評論。
我們需要檢測一個外部程序的完成,這個腳本還沒有啓動。該問題詢問使用waitpid
。複製我的早評:
你不能。您只能等待子進程。見
perldoc wait
(或waitpid
,這是一樣的),第一句話。
wait
和waitpid
等待傳遞給腳本的關於其子(命令)的命運的信號。腳本沒有理由接收有關它沒有啓動的進程的信號。
我們知道進程的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'`
的egrep
是grep -E
運行進行測試。 `ps ...`
的輸出包含多個單詞。這些作爲命令行參數傳遞給我們的腳本,該腳本使用第一個作爲PID。如果出現問題,請先運行ps
篩選,然後手動輸入PID作爲腳本的輸入參數。上面30秒的sleep
是給予足夠的時間在命令行上完成所有這些。
如果程序名稱足夠獨特且不會更改,則可以通過將$name
與硬編碼的$prog_name
進行匹配來簡化代碼。 上面使用的硬編碼名稱是,但是對於檢查,如果不匹配,它會生成警告。如果這個過程是由相同的用戶腳本可以使用kill 0, $pid
資(如果我們依靠它只能硬編碼,我們不能發出警告,如果不匹配,因爲這是隨後的代碼的操作的一部分。)
作爲
while (kill 0, $ext_pid) { sleep 1 }
然後,你要麼必須撥打另一個電話,以檢查名稱或滿足於在什麼實際過程中$pid
表示錯誤的(小)的可能性。
模塊Proc::ProcessTable
可以用於所有這些。在Windows系統上,這將是一條路。
是的,它爲我工作 – user3395103
@ user3395103很高興工作。結果是一個很長的帖子,讓我知道是否有任何問題或問題。 – zdim
等待特定子進程終止,並返回死者進程的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(不太可能,但可能)。
您確定'$ pid'是您認爲的嗎? 'waitpid'的返回值是什麼?它將指示什麼進程終止。 – Schwern
@Schwern - waitpid的返回值是-1。這意味着我沒有這樣的孩子過程。我添加下面的行來檢查$ pid是否正在運行。我的$ exists = kill 0,$ pid; ($存在);打印「進程正在運行\ n」( );並且它會打印語句 – user3395103
您不能。您只能在子進程上「等待」。請參閱'perldoc wait'(或'waitpid',這是一樣的),第一句。如果你想知道外部程序何時完成,你必須做完全不同的事情。 – zdim