perl - 当正在运行的进程不是子进程时,如何在 perl 中等待正在运行的进程完成?

标签 perl waitpid

我正在浏览一个正在使用的 Perl 脚本 waitpid($pid, 0) 等待当前进程完成。 但是在这个 waitpid 之后编写的 print 语句在进程完成之前打印它。

我想知道为什么 waitpid 不先等待进程完成。

此外,运行过程的控制在不同的模块下,而不是这个 perl 脚本的一部分。只能访问进程的 pid 和名称。我无法更改调用该流程的模块中的任何内容。

最佳答案

注意 一个带有kill 0, $pid 的简单的单行代码在最后,注释掉了。


我们需要检测外部程序的完成情况,该程序尚未由该脚本启动。该问题询问有关使用 waitpid 的问题。要复制我的早期评论:

You cannot. You can only wait on a child process. See perldoc wait (or waitpid, it's the same), first sentence.

waitwaitpid 等待传递给脚本的关于其子进程(ren)命运的信号。脚本没有理由接收有关它未启动的进程的此类信号。


我们知道进程的 ID 和名称。它的 PID 可用于轮询它是否正在运行。单独使用 pid 并不完全可靠,因为在我们的检查过程中,进程可以完成,并且一个随机的新进程被分配相同的 pid。我们可以使用程序的名称来加强这一点。

在 Linux 系统上,可以通过使用(许多)ps 选项获取有关进程的信息。这些中的任何一个都返回程序的完整调用

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

The returned string may start with the interpreter's path (for a Perl script, for example), followed by the program's full name. The version ps -p PID -o comm= returns only the program's name, but I find that it may break that word on a hyphen (if there), resulting in an incomplete name. This may need tweaking on some systems, please consult your man ps. If there is no process with given PID we get nothing back.

Then we can check for PID and if found check whether the name for that PID matches the program. The program's name is known and we could just hardcode that. However, it is still obtained by the script as it starts, using the above ps command, to avoid ambiguities. (Then it is also in the same format for later comparison.) This itself is checked against the known name since there is no guarantee that the PID at the time of script execution is indeed for the expected program.

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 编辑,这需要稍作调整。剩下的漏洞是那个程序可能已经完成并在检查之间重新启动,并且具有相同的 PID。

这将通过在 shell 中运行来测试

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

The egrep is grep -E. The output from `ps ...` contains multiple words. These are passed as command line arguments to our script, which uses the first one as the PID. If there is a problem with it run the ps filtering first and then manually enter the PID as script's input argument. The sleep of 30 seconds above is to give enough time to do all this on the command line.

The code can be simplified by matching $name with a hard-coded $prog_name, if the program name is unique enough and it will not change. The hard-coded name is used above, but for a check and it generates a warning if mismatched. (If we rely on it only hardcoded we cannot issue warnings if it mismatches, since that is then a part of code's operation.)


If the process is owned by the same user as the script one can use kill 0, $pid, as

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

然后您要么必须再次调用以检查名称,要么满足于 $pid 代表的实际过程中出现错误的(小)可能性。

模块Proc::ProcessTable可以用于其中的大部分内容

关于perl - 当正在运行的进程不是子进程时,如何在 perl 中等待正在运行的进程完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37269040/

相关文章:

子进程在运行 fork() 时接管父进程

perl - 如何确定对象或引用是否具有有效的字符串强制转换?

python - 以数字序列+字母重命名文件

bash - Perl 从命令行脚本打印单引号

c - fork/exec/waitpid 问题

c - 为什么 wait4() 被 waitpid() 取代

perl - 如何在 Perl XS 中处理哈希值类型

regex - 有没有更好的方法来模拟\x插值?

c - Unix-Waitpid 'status'

perl - 如果间隔计时器事件始终准备就绪,为什么 AnyEvent::child 回调不会运行?