Perl - 进程管理

您可以根据需要以各种方式使用 Perl 来创建新流程。 本教程将列出创建和管理 Perl 进程的几个重要和最常用的方法。

  • 您可以使用特殊变量 $$$PROCESS_ID 来获取当前进程 ID。

  • 使用上述任何方法创建的每个进程都在 %ENV 变量中维护自己的虚拟环境。

  • exit() 函数总是只退出执行该函数的子进程,而主进程作为一个整体不会退出,除非所有正在运行的子进程都已退出。

  • 所有打开的句柄在子进程中都是 dup()-ed,因此关闭一个进程中的任何句柄不会影响其他进程。


backstick 运算符

执行任何 Unix 命令的最简单方法是使用 backstick 运算符。 您只需将命令放在 backstick 运算符中,这将导致命令执行并返回其结果,该结果可以存储如下 −

#!/usr/bin/perl

@files = `ls -l`;

foreach $file (@files) {
   print $file;
}

1;

执行上述代码时,它会列出当前目录中所有可用的文件和目录 −

drwxr-xr-x 3 root root 4096 Sep 14 06:46 9-14
drwxr-xr-x 4 root root 4096 Sep 13 07:54 android
-rw-r--r-- 1 root root  574 Sep 17 15:16 index.htm
drwxr-xr-x 3  544  401 4096 Jul  6 16:49 MIME-Lite-3.01
-rw-r--r-- 1 root root   71 Sep 17 15:16 test.pl
drwx------ 2 root root 4096 Sep 17 15:11 vAtrJdy

system() 函数

您也可以使用 system() 函数来执行任何 Unix 命令,其输出将转到 perl 脚本的输出。 默认情况下,它是屏幕,即 STDOUT,但您可以使用重定向运算符 > 将其重定向到任何文件 −

#!/usr/bin/perl

system( "ls -l")

1;

执行上述代码时,它会列出当前目录中可用的所有文件和目录 −

drwxr-xr-x 3 root root 4096 Sep 14 06:46 9-14
drwxr-xr-x 4 root root 4096 Sep 13 07:54 android
-rw-r--r-- 1 root root  574 Sep 17 15:16 index.htm
drwxr-xr-x 3  544  401 4096 Jul  6 16:49 MIME-Lite-3.01
-rw-r--r-- 1 root root   71 Sep 17 15:16 test.pl
drwx------ 2 root root 4096 Sep 17 15:11 vAtrJdy

当您的命令包含诸如 $PATH 或 $HOME 之类的 shell 环境变量时要小心。 尝试以下三种情况 −

#!/usr/bin/perl

$PATH = "I am Perl Variable";

system('echo $PATH');  # Treats $PATH as shell variable
system("echo $PATH");  # Treats $PATH as Perl variable
system("echo \$PATH"); # Escaping $ works.

1;

执行上述代码时,它会根据 shell 变量 $PATH 中设置的内容产生以下结果。

/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin
I am Perl Variable
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin

fork() 函数

Perl 提供了一个 fork() 函数,对应于同名的 Unix 系统调用。 在大多数可以使用 fork() 系统调用的类 Unix 平台上,Perl 的 fork() 简单地调用它。 在某些平台(例如 Windows)上 fork() 系统调用不可用,可以构建 Perl 以在解释器级别模拟 fork()。

fork() 函数用于克隆当前进程。 此调用创建一个在同一点运行同一程序的新进程。 它将子pid返回给父进程,0返回给子进程,如果fork不成功则返回undef。

您可以在进程中使用 exec() 函数来启动请求的可执行文件,该可执行文件将在单独的进程区域中执行,并且 exec() 将等待它完成,然后以相同的方式退出 作为该进程的退出状态。

#!/usr/bin/perl

if(!defined($pid = fork())) {
   # fork returned undef, so unsuccessful
   die "Cannot fork a child: $!";
} elsif ($pid == 0) {
   print "Printed by child process\n";
   exec("date") || die "can't exec date: $!";
  
} else {
   # fork returned 0 nor undef
   # so this branch is parent
   print "Printed by parent process\n";
   $ret = waitpid($pid, 0);
   print "Completed process id: $ret\n";

}

1;

执行上述代码时,会产生以下结果 −

Printed by parent process
Printed by child process
Tue Sep 17 15:41:08 CDT 2013
Completed process id: 17777

wait()waitpid() 可以作为 fork() 返回的伪进程 ID 传递。 这些调用将正确等待伪进程的终止并返回其状态。 如果你使用 waitpid() 函数在没有等待你的孩子的情况下分叉,你会积累僵尸。 在 Unix 系统上,您可以通过将 $SIG{CHLD} 设置为"IGNORE"来避免这种情况,如下所示 −

#!/usr/bin/perl

local $SIG{CHLD} = "IGNORE";
 
if(!defined($pid = fork())) {
   # fork returned undef, so unsuccessful
   die "Cannot fork a child: $!";
} elsif ($pid == 0) {
   print "Printed by child process\n";
   exec("date") || die "can't exec date: $!";
  
} else {
   # fork returned 0 nor undef
   # so this branch is parent
   print "Printed by parent process\n";
   $ret = waitpid($pid, 0);
   print "Completed process id: $ret\n";

}

1;

执行上述代码时,会产生以下结果 −

Printed by parent process
Printed by child process
Tue Sep 17 15:44:07 CDT 2013
Completed process id: -1

kill() 函数

Perl kill('KILL', (Process List)) 函数可用于通过将 fork() 返回的 ID 传递给伪进程来终止伪进程。

请注意,在伪进程()上使用 kill('KILL', (Process List)) 通常可能会导致内存泄漏,因为实现伪进程的线程没有机会清理其资源。

您可以使用 kill() 函数向目标进程发送任何其他信号,例如以下将向进程 ID 104 和 102 发送 SIGINT −

#!/usr/bin/perl

kill('INT', 104, 102);
 
1;