如何避免<defunct>进程?

我从主控主机到从属主机执行ZFS远程复制,在那里我有一个在主控主机上运行的Perl脚本。

对于每个文件系统,ssh到远程主机,并在监听模式下启动mbuffer,然后脚本继续,然后发送数据。 成功时,mbuffer应该自行退出。

问题

通过ssh在远程主机上启动mbuffer是非常困难的,然后能够在脚本中继续运行。 我结束了你在下面看到的事情。

问题是,直到脚本退出,它留下<defunct>为每个文件系统处理一个。

有可能避免<defunct>进程?

 sub mbuffer { my ($id, $zfsPath) = @_; my $m = join(' ', $mbuffer, '-I', $::c{port}); my $z = join(' ', $zfs, 'receive', , $zfsPath); my $c = shellQuote($ssh, $::c{slaves}{$id}, join('|', $m, $z)); my $pm = Parallel::ForkManager->new(1); my $pid = $pm->start; if (!$pid) { no warnings; # fixes "exec" not working exec($c); $pm->finish; } sleep 3; # wait for mbuffer to listen return $pid; } 

当你创建一个进程时,它会一直持续下去,直到父进程完成。 (如果其父节点首先退出,则会自动获得。)进程可以使用waitwaitpid获取其子waitpid 。 也可以通过使用local $SIG{CHLD} = 'IGNORE';来自动获得孩子的local $SIG{CHLD} = 'IGNORE'; 在创造孩子之前。


请注意,Parallel :: ForkManager并不是启动一个孩子的正确工具。 产生一个单独的工作人员不是目的。

 use String::ShellQuote qw( shell_quote ); sub mbuffer { my ($id, $zfsPath) = @_; my $mbuffer_cmd = shell_quote($mbuffer, '-I', $::c{port}); my $zfs_cmd = shell_quote($zfs, 'receive', $zfsPath); my $remote_cmd = "$mbuffer_cmd | $zfs_cmd"; my $local_cmd = shell_quote($ssh, $::c{slaves}{$id}, $remote_cmd); # open3 will close this handle. # open3 doesn't deal well with lexical handles. open(local *CHILD_STDIN, '<', '/dev/null') or die $!; return open3('<&CHILD_STDIN', '>&STDOUT', '>&STDERR', $local_cmd); } 

IPC :: Open3是相当低的水平,但它是最接近你现有的代码。 启动进程的更好方法包括IPC :: Run3和IPC :: Run。

首先,没有理由在一个进程中使用P::FM 。 此外,由于您放弃了对流程管理的更好控制,因此在这里是不利的。

但是直接的错误在于使用exec ; 这个职位只解决这个问题。

exec调用将另一个程序中的内容替换掉 , 永远不会返回 。 因此, exec后的子代码不运行(请参阅文档)。 因此, $pm->finish悬而未决,子进程永远不会被收获,并且操作系统在进程表中保存它的信息,所以有一个不存在的/僵尸。

这是一个使用exec直接启动另一个程序的基本方法

 my $cmd = '...'; my $pid = fork // die "Can't fork: $!"; if ($pid == 0) { exec $cmd; die "exec shouldn't return: $!"; } my $gone = waitpid $pid, 0; if ($gone > 0) { say "Child $gone exited with $?" } elsif ($gone < 0) { say "No $pid process ($gone), reaped already?" } else { say "Process $pid still running?" } 

这里的孩子继承父母的标准流。 此外,在某些情况下,错误报告是粗略的(不精确),请参阅ikegami的评论。

在ikegami的回答中,更详细和忠实地替代你所做的事情。