流程管理(Process Management)
您可以通过各种方式使用Perl来根据您的要求创建新流程。 本教程将列出几个重要且最常用的创建和管理Perl进程的方法。
您可以使用特殊变量$$或$PROCESS_ID来获取当前进程ID。
使用任何上述方法创建的每个进程都使用%ENV变量维护自己的虚拟环境。
exit()函数总是只退出执行此函数的子进程,并且除非所有正在运行的子进程都已退出,否则整个主进程不会退出。
所有打开的句柄都是子进程中的dup() - 因此在一个进程中关闭任何句柄不会影响其他句柄。
Backstick Operator
执行任何Unix命令的最简单方法是使用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
The system() Function
您还可以使用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
The fork() Function
Perl提供了一个fork()函数,它对应于同名的Unix系统调用。 在大多数类似于Unix的平台上,fork()系统调用可用,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
The kill() Function
Perl kill('KILL', (Process List))函数可以通过传递fork()返回的ID来终止伪进程。
请注意,在伪进程()上使用kill('KILL',(进程列表))通常可能导致内存泄漏,因为实现伪进程的线程没有机会清理其资源。
您可以使用kill()函数将任何其他信号发送到目标进程,例如,以下将SIGINT发送到进程ID 104和102 -
#!/usr/bin/perl
kill('INT', 104, 102);
1;