Perl 進程管理


Perl 中你可以用不同的方法來建立進程。

本教學將討論一些進程的管理方法。

  • 你可以使用特殊變數 $$$PROCESS_ID 來取得進程 ID。

  • %ENV 哈希存放了父進程,也就是shell中的環境變量,在Perl中可以修改這些變數。

  • exit() 通常用於退出子進程,主進程在子進程全部退出後再退出。

  • 所有開啟的句柄會在子程式中被 dup() 函式複製, 所有關閉程序所有句柄不會影響其他行程 。


反引號運算子

使用反引號運算子可以很容易的執行 Unix 指令。你可以在反引號中插入一些簡單的指令。指令執行後會傳回結果:

#!/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
……

system() 函數

你也可以使用system () 函數執行Unix 指令,  執行指令將直接輸出結果。預設會送到目前Perl的STDOUT指向的地方,通常是螢幕。你也可以使用重定向運算子> 輸出到指定檔:

執行以上程序,輸出結果如下:

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
……

你需要注意指令包含環境變數如$PATH 或$HOME的輸出結果,如下所示:

#!/usr/bin/perl

$PATH = "我是 Perl 的变量";

system('echo $PATH');  # $PATH 作为 shell 环境变量
system("echo $PATH");  # $PATH 作为 Perl 的变量
system("echo $PATH"); # 转义 $

1;

執行以上程序,輸出結果如下:

/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin
我是 Perl 的变量
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin

fork() 函數

Perl fork() 函數用於創建一個新進程。

在父進程中傳回子進程的PID,在子進程中回傳0。如果發生錯誤(例如,記憶體不足)傳回undef,並將$!設為對應的錯誤訊息。

fork 可以和 exec 搭配使用。 exec 函數執行完引號中的命令後進程即結束。

#!/usr/bin/perl

if(!defined($pid = fork())) {
   # fork 发生错误返回 undef
   die "无法创建子进程: $!";
}elsif ($pid == 0) {
   print "通过子进程输出\n";
   exec("date") || die "无法输出日期: $!";
  
} else {
   # 在父进程中
   print "通过父进程输出\n";
   $ret = waitpid($pid, 0);
   print "完成的进程ID: $ret\n";

}

1;

執行以上程序,輸出結果如下:

通过父进程输出
通过子进程输出
2016年 6月19日 星期日 22时21分14秒 CST
完成的进程ID: 47117

如果進程退出時,會向父進程發送一個CHLD的信號後,就會變成僵死的進程,需要父進程使用wait和waitpid來終止。當然,也可以設定$SIG{CHLD}為IGNORG:

#!/usr/bin/perl

local $SIG{CHLD} = "IGNORE";
 
if(!defined($pid = fork())) {
   # fork 发生错误返回 undef
   die "无法创建子进程: $!";
}elsif ($pid == 0) {
   print "通过子进程输出\n";
   exec("date") || die "无法输出日期: $!";
  
} else {
   # 在父进程中
   print "通过父进程输出\n";
   $ret = waitpid($pid, 0);
   print "完成的进程ID: $ret\n";

}

1;

執行以上程序,輸出結果如下:

通过父进程输出
通过子进程输出
2016年 6月19日 星期日 22时30分56秒 CST
完成的进程ID: -1

Kill 函數

#Perl kill('signal', (Process List))給一組程序發送訊號。 signal是發送的數位訊號,9為殺死進程。

首先看看linux中的常用訊號,見如下列表:

信号名          值          标注          解释
————————————————————————————————————————————————————————————
HUP             1           A             检测到挂起
INT               2           A             来自键盘的中断
QUIT            3           A             来自键盘的停止
ILL               4           A             非法指令
ABRT          6           C             失败
FPE             8           C             浮点异常
KILL             9           AF            终端信号
USR1          10          A             用户定义的信号1
SEGV          11          C             非法内存访问
USR2          12          A             用户定义的信号2
PIPE           13          A             写往没有读取者的管道
ALRM         14          A             来自闹钟的定时器信号
TERM         15          A             终端信号
CHLD          17          B             子进程终止
CONT         18          E             如果被停止则继续
STOP         19          DF            停止进程
TSTP          20          D             tty键入的停止命令
TTIN            21          D             对后台进程的tty输入
TTOU          22          D             对后台进程的tty输出

以下實例向進程 104 和 102 發送 SIGINT 訊號:

#!/usr/bin/perl

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